import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.AlignmentOrder;
+import jalview.datamodel.BinaryNode;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
*
* @return DOCUMENT ME!
*/
- private static List<SequenceI> _sortByTree(SequenceNode node,
+ private static List<SequenceI> _sortByTree(BinaryNode node,
List<SequenceI> tmp, List<SequenceI> seqset)
{
if (node == null)
return tmp;
}
- SequenceNode left = (SequenceNode) node.left();
- SequenceNode right = (SequenceNode) node.right();
+ BinaryNode left = (BinaryNode) node.left();
+ BinaryNode right = (BinaryNode) node.right();
if ((left == null) && (right == null))
{
- if (!node.isPlaceholder() && (node.element() != null))
+ if (!(node instanceof SequenceNode && ((SequenceNode)node).isPlaceholder()) && (node.element() != null))
{
if (node.element() instanceof SequenceI)
{
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.analysis;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.List;
+import java.util.Vector;
+
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.BinaryNode;
+import jalview.datamodel.ContactListI;
+import jalview.datamodel.ContactMatrixI;
+import jalview.math.Matrix;
+import jalview.viewmodel.AlignmentViewport;
+
+/**
+ * This class implements distance calculations used in constructing a Average
+ * Distance tree (also known as UPGMA)
+ */
+public class AverageDistanceEngine extends TreeEngine
+{
+ ContactMatrixI cm;
+
+ AlignmentViewport av;
+
+ AlignmentAnnotation aa;
+
+ /**
+ * compute cosine distance matrix for a given contact matrix and create a
+ * UPGMA tree
+ *
+ * @param cm
+ */
+ public AverageDistanceEngine(AlignmentViewport av, AlignmentAnnotation aa,
+ ContactMatrixI cm)
+ {
+ this.av = av;
+ this.aa = aa;
+ this.cm = cm;
+ calculate(cm);
+
+ }
+
+ // 0 - normalised dot product
+ // 1 - L1 - ie (abs(v_1-v_2)/dim(v))
+ // L1 is more rational - since can reason about value of difference,
+ // normalised dot product might give cleaner clusters, but more difficult to
+ // understand.
+
+ int mode = 1;
+
+ public void calculate(ContactMatrixI cm)
+ {
+ this.cm = cm;
+ node = new Vector<BinaryNode>();
+ clusters = new Vector<BitSet>();
+ distances = new Matrix(new double[cm.getWidth()][cm.getWidth()]);
+ noseqs = cm.getWidth();
+ done = new BitSet();
+ double moduli[] = new double[cm.getWidth()];
+ double max;
+ if (mode == 0)
+ {
+ max = 1;
+ }
+ else
+ {
+ max = cm.getMax() * cm.getMax();
+ }
+
+ for (int i = 0; i < cm.getWidth(); i++)
+ {
+ // init the tree engine node for this column
+ BinaryNode cnode = new BinaryNode();
+ cnode.setElement(Integer.valueOf(i));
+ cnode.setName("c" + i);
+ node.addElement(cnode);
+ BitSet bs = new BitSet();
+ bs.set(i);
+ clusters.addElement(bs);
+
+ // compute distance matrix element
+ ContactListI ith = cm.getContactList(i);
+
+ for (int j = 0; j < i; j++)
+ {
+ distances.setValue(i, i, 0);
+ ContactListI jth = cm.getContactList(j);
+ double prd = 0;
+ for (int indx = 0; indx < cm.getHeight(); indx++)
+ {
+ if (mode == 0)
+ {
+ if (j == 0)
+ {
+ moduli[i] += ith.getContactAt(indx) * ith.getContactAt(indx);
+ }
+ prd += ith.getContactAt(indx) * jth.getContactAt(indx);
+ }
+ else
+ {
+ prd += Math
+ .abs(ith.getContactAt(indx) - jth.getContactAt(indx));
+ }
+ }
+ if (mode == 0)
+ {
+ if (j == 0)
+ {
+ moduli[i] = Math.sqrt(moduli[i]);
+ }
+ prd = (moduli[i] != 0 && moduli[j] != 0)
+ ? prd / (moduli[i] * moduli[j])
+ : 0;
+ prd = 1 - prd;
+ }
+ else
+ {
+ prd /= cm.getHeight();
+ }
+ distances.setValue(i, j, prd);
+ distances.setValue(j, i, prd);
+ }
+ }
+
+ noClus = clusters.size();
+ cluster();
+ }
+
+ /**
+ * Calculates and saves the distance between the combination of cluster(i) and
+ * cluster(j) and all other clusters. An average of the distances from
+ * cluster(i) and cluster(j) is calculated, weighted by the sizes of each
+ * cluster.
+ *
+ * @param i
+ * @param j
+ */
+ @Override
+ protected void findClusterDistance(int i, int j)
+ {
+ int noi = clusters.elementAt(i).cardinality();
+ int noj = clusters.elementAt(j).cardinality();
+
+ // New distances from cluster i to others
+ double[] newdist = new double[noseqs];
+
+ for (int l = 0; l < noseqs; l++)
+ {
+ if ((l != i) && (l != j))
+ {
+ newdist[l] = ((distances.getValue(i, l) * noi)
+ + (distances.getValue(j, l) * noj)) / (noi + noj);
+ }
+ else
+ {
+ newdist[l] = 0;
+ }
+ }
+
+ for (int ii = 0; ii < noseqs; ii++)
+ {
+ distances.setValue(i, ii, newdist[ii]);
+ distances.setValue(ii, i, newdist[ii]);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected double findMinDistance()
+ {
+ double min = Double.MAX_VALUE;
+
+ for (int i = 0; i < (noseqs - 1); i++)
+ {
+ for (int j = i + 1; j < noseqs; j++)
+ {
+ if (!done.get(i) && !done.get(j))
+ {
+ if (distances.getValue(i, j) < min)
+ {
+ mini = i;
+ minj = j;
+
+ min = distances.getValue(i, j);
+ }
+ }
+ }
+ }
+ return min;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void findNewDistances(BinaryNode nodei, BinaryNode nodej,
+ double dist)
+ {
+ double ih = 0;
+ double jh = 0;
+
+ BinaryNode sni = nodei;
+ BinaryNode snj = nodej;
+
+ while (sni != null)
+ {
+ ih = ih + sni.dist;
+ sni = (BinaryNode) sni.left();
+ }
+
+ while (snj != null)
+ {
+ jh = jh + snj.dist;
+ snj = (BinaryNode) snj.left();
+ }
+
+ nodei.dist = ((dist / 2) - ih);
+ nodej.dist = ((dist / 2) - jh);
+ }
+
+ /***
+ * not the right place - OH WELL!
+ */
+
+ /**
+ * Makes a list of groups, where each group is represented by a node whose
+ * height (distance from the root node), as a fraction of the height of the
+ * whole tree, is greater than the given threshold. This corresponds to
+ * selecting the nodes immediately to the right of a vertical line
+ * partitioning the tree (if the tree is drawn with root to the left). Each
+ * such node represents a group that contains all of the sequences linked to
+ * the child leaf nodes.
+ *
+ * @param threshold
+ * @see #getGroups()
+ */
+ public List<BinaryNode> groupNodes(float threshold)
+ {
+ List<BinaryNode> groups = new ArrayList<BinaryNode>();
+ _groupNodes(groups, getTopNode(), threshold);
+ return groups;
+ }
+
+ protected void _groupNodes(List<BinaryNode> groups, BinaryNode nd,
+ float threshold)
+ {
+ if (nd == null)
+ {
+ return;
+ }
+
+ if ((nd.height / maxheight) > threshold)
+ {
+ groups.add(nd);
+ }
+ else
+ {
+ _groupNodes(groups, nd.left(), threshold);
+ _groupNodes(groups, nd.right(), threshold);
+ }
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param nd
+ * DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ public double findHeight(BinaryNode nd)
+ {
+ if (nd == null)
+ {
+ return maxheight;
+ }
+
+ if ((nd.left() == null) && (nd.right() == null))
+ {
+ nd.height = ((BinaryNode) nd.parent()).height + nd.dist;
+
+ if (nd.height > maxheight)
+ {
+ return nd.height;
+ }
+ else
+ {
+ return maxheight;
+ }
+ }
+ else
+ {
+ if (nd.parent() != null)
+ {
+ nd.height = ((BinaryNode) nd.parent()).height + nd.dist;
+ }
+ else
+ {
+ maxheight = 0;
+ nd.height = (float) 0.0;
+ }
+
+ maxheight = findHeight((BinaryNode) (nd.left()));
+ maxheight = findHeight((BinaryNode) (nd.right()));
+ }
+
+ return maxheight;
+ }
+
+ /**
+ * Search for leaf nodes below (or at) the given node
+ *
+ * @param top2
+ * root node to search from
+ *
+ * @return
+ */
+ public Vector<BinaryNode> findLeaves(BinaryNode top2)
+ {
+ Vector<BinaryNode> leaves = new Vector<BinaryNode>();
+ findLeaves(top2, leaves);
+ return leaves;
+ }
+
+ /**
+ * Search for leaf nodes.
+ *
+ * @param nd
+ * root node to search from
+ * @param leaves
+ * Vector of leaves to add leaf node objects too.
+ *
+ * @return Vector of leaf nodes on binary tree
+ */
+ Vector<BinaryNode> findLeaves(BinaryNode nd, Vector<BinaryNode> leaves)
+ {
+ if (nd == null)
+ {
+ return leaves;
+ }
+
+ if ((nd.left() == null) && (nd.right() == null)) // Interior node
+ // detection
+ {
+ leaves.addElement(nd);
+
+ return leaves;
+ }
+ else
+ {
+ /*
+ * TODO: Identify internal nodes... if (node.isSequenceLabel()) {
+ * leaves.addElement(node); }
+ */
+ findLeaves(nd.left(), leaves);
+ findLeaves(nd.right(), leaves);
+ }
+
+ return leaves;
+ }
+
+}
import jalview.api.analysis.ScoreModelI;
import jalview.api.analysis.SimilarityParamsI;
-import jalview.datamodel.SequenceNode;
+import jalview.datamodel.BinaryNode;
import jalview.viewmodel.AlignmentViewport;
/**
* {@inheritDoc}
*/
@Override
- protected void findNewDistances(SequenceNode nodei, SequenceNode nodej,
+ protected void findNewDistances(BinaryNode nodei, BinaryNode nodej,
double dist)
{
double ih = 0;
double jh = 0;
- SequenceNode sni = nodei;
- SequenceNode snj = nodej;
+ BinaryNode sni = nodei;
+ BinaryNode snj = nodej;
while (sni != null)
{
ih = ih + sni.dist;
- sni = (SequenceNode) sni.left();
+ sni = (BinaryNode) sni.left();
}
while (snj != null)
{
jh = jh + snj.dist;
- snj = (SequenceNode) snj.left();
+ snj = (BinaryNode) snj.left();
}
nodei.dist = ((dist / 2) - ih);
import jalview.api.analysis.ScoreModelI;
import jalview.api.analysis.SimilarityParamsI;
-import jalview.datamodel.SequenceNode;
+import jalview.datamodel.BinaryNode;
import jalview.viewmodel.AlignmentViewport;
/**
* {@inheritDoc}
*/
@Override
- protected void findNewDistances(SequenceNode nodei, SequenceNode nodej,
+ protected void findNewDistances(BinaryNode nodei, BinaryNode nodej,
double dist)
{
nodei.dist = ((dist + ri) - rj) / 2;
import jalview.api.analysis.ScoreModelI;
import jalview.api.analysis.SimilarityParamsI;
import jalview.datamodel.AlignmentView;
+import jalview.datamodel.BinaryNode;
import jalview.datamodel.CigarArray;
import jalview.datamodel.SeqCigar;
import jalview.datamodel.SequenceI;
import jalview.datamodel.SequenceNode;
-import jalview.math.MatrixI;
import jalview.viewmodel.AlignmentViewport;
import java.util.BitSet;
import java.util.Vector;
-public abstract class TreeBuilder
+public abstract class TreeBuilder extends TreeEngine
{
public static final String AVERAGE_DISTANCE = "AV";
public static final String NEIGHBOUR_JOINING = "NJ";
- protected Vector<BitSet> clusters;
-
protected SequenceI[] sequences;
public AlignmentView seqData;
- protected BitSet done;
-
- protected int noseqs;
-
- int noClus;
-
- protected MatrixI distances;
-
- protected int mini;
-
- protected int minj;
-
- protected double ri;
-
- protected double rj;
-
- SequenceNode maxdist;
-
- SequenceNode top;
-
- double maxDistValue;
-
- double maxheight;
-
- int ycount;
-
- Vector<SequenceNode> node;
-
private AlignmentView seqStrings;
/**
}
/**
- * DOCUMENT ME!
- *
- * @param nd
- * DOCUMENT ME!
- *
- * @return DOCUMENT ME!
- */
- double findHeight(SequenceNode nd)
- {
- if (nd == null)
- {
- return maxheight;
- }
-
- if ((nd.left() == null) && (nd.right() == null))
- {
- nd.height = ((SequenceNode) nd.parent()).height + nd.dist;
-
- if (nd.height > maxheight)
- {
- return nd.height;
- }
- else
- {
- return maxheight;
- }
- }
- else
- {
- if (nd.parent() != null)
- {
- nd.height = ((SequenceNode) nd.parent()).height + nd.dist;
- }
- else
- {
- maxheight = 0;
- nd.height = (float) 0.0;
- }
-
- maxheight = findHeight((SequenceNode) (nd.left()));
- maxheight = findHeight((SequenceNode) (nd.right()));
- }
-
- return maxheight;
- }
-
- /**
- * DOCUMENT ME!
- *
- * @param nd
- * DOCUMENT ME!
- */
- void reCount(SequenceNode nd)
- {
- ycount = 0;
- // _lycount = 0;
- // _lylimit = this.node.size();
- _reCount(nd);
- }
-
- /**
- * DOCUMENT ME!
- *
- * @param nd
- * DOCUMENT ME!
- */
- void _reCount(SequenceNode nd)
- {
- // if (_lycount<_lylimit)
- // {
- // System.err.println("Warning: depth of _recount greater than number of
- // nodes.");
- // }
- if (nd == null)
- {
- return;
- }
- // _lycount++;
-
- if ((nd.left() != null) && (nd.right() != null))
- {
-
- _reCount((SequenceNode) nd.left());
- _reCount((SequenceNode) nd.right());
-
- SequenceNode l = (SequenceNode) nd.left();
- SequenceNode r = (SequenceNode) nd.right();
-
- nd.count = l.count + r.count;
- nd.ycount = (l.ycount + r.ycount) / 2;
- }
- else
- {
- nd.count = 1;
- nd.ycount = ycount++;
- }
- // _lycount--;
- }
-
- /**
- * DOCUMENT ME!
- *
- * @return DOCUMENT ME!
- */
- public SequenceNode getTopNode()
- {
- return top;
- }
-
- /**
*
* @return true if tree has real distances
*/
}
/**
- * Form clusters by grouping sub-clusters, starting from one sequence per
- * cluster, and finishing when only two clusters remain
- */
- void cluster()
- {
- while (noClus > 2)
- {
- findMinDistance();
-
- joinClusters(mini, minj);
-
- noClus--;
- }
-
- int rightChild = done.nextClearBit(0);
- int leftChild = done.nextClearBit(rightChild + 1);
-
- joinClusters(leftChild, rightChild);
- top = (node.elementAt(leftChild));
-
- reCount(top);
- findHeight(top);
- findMaxDist(top);
- }
-
- /**
- * Returns the minimum distance between two clusters, and also sets the
- * indices of the clusters in fields mini and minj
- *
- * @return
- */
- protected abstract double findMinDistance();
-
- /**
* Calculates the tree using the given score model and parameters, and the
* configured tree type
* <p>
cluster();
}
- /**
- * Finds the node, at or below the given node, with the maximum distance, and
- * saves the node and the distance value
- *
- * @param nd
- */
- void findMaxDist(SequenceNode nd)
- {
- if (nd == null)
- {
- return;
- }
-
- if ((nd.left() == null) && (nd.right() == null))
- {
- double dist = nd.dist;
-
- if (dist > maxDistValue)
- {
- maxdist = nd;
- maxDistValue = dist;
- }
- }
- else
- {
- findMaxDist((SequenceNode) nd.left());
- findMaxDist((SequenceNode) nd.right());
- }
- }
-
- /**
- * Calculates and returns r, whatever that is
- *
- * @param i
- * @param j
- *
- * @return
- */
- protected double findr(int i, int j)
- {
- double tmp = 1;
-
- for (int k = 0; k < noseqs; k++)
- {
- if ((k != i) && (k != j) && (!done.get(k)))
- {
- tmp = tmp + distances.getValue(i, k);
- }
- }
-
- if (noClus > 2)
- {
- tmp = tmp / (noClus - 2);
- }
-
- return tmp;
- }
-
protected void init(AlignmentView seqView, int start, int end)
{
- this.node = new Vector<SequenceNode>();
+ this.node = new Vector<BinaryNode>();
if (seqView != null)
{
this.seqData = seqView;
}
/**
- * Merges cluster(j) to cluster(i) and recalculates cluster and node distances
- *
- * @param i
- * @param j
- */
- void joinClusters(final int i, final int j)
- {
- double dist = distances.getValue(i, j);
-
- ri = findr(i, j);
- rj = findr(j, i);
-
- findClusterDistance(i, j);
-
- SequenceNode sn = new SequenceNode();
-
- sn.setLeft((node.elementAt(i)));
- sn.setRight((node.elementAt(j)));
-
- SequenceNode tmpi = (node.elementAt(i));
- SequenceNode tmpj = (node.elementAt(j));
-
- findNewDistances(tmpi, tmpj, dist);
-
- tmpi.setParent(sn);
- tmpj.setParent(sn);
-
- node.setElementAt(sn, i);
-
- /*
- * move the members of cluster(j) to cluster(i)
- * and mark cluster j as out of the game
- */
- clusters.get(i).or(clusters.get(j));
- clusters.get(j).clear();
- done.set(j);
- }
-
- /*
- * Computes and stores new distances for nodei and nodej, given the previous
- * distance between them
- */
- protected abstract void findNewDistances(SequenceNode nodei,
- SequenceNode nodej, double previousDistance);
-
- /**
- * Calculates and saves the distance between the combination of cluster(i) and
- * cluster(j) and all other clusters. The form of the calculation depends on
- * the tree clustering method being used.
- *
- * @param i
- * @param j
- */
- protected abstract void findClusterDistance(int i, int j);
-
- /**
* Start by making a cluster for each individual sequence
*/
void makeLeaves()
--- /dev/null
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.analysis;
+
+import java.util.BitSet;
+import java.util.Vector;
+
+import jalview.datamodel.BinaryNode;
+import jalview.datamodel.SequenceNode;
+import jalview.math.MatrixI;
+
+public abstract class TreeEngine
+{
+
+ protected Vector<BitSet> clusters;
+
+ protected BitSet done;
+
+ protected int noseqs;
+
+ protected int noClus;
+
+ protected MatrixI distances;
+
+ protected double ri;
+
+ protected double rj;
+
+ protected Vector<BinaryNode> node;
+
+ BinaryNode maxdist;
+
+ double maxDistValue;
+
+ protected int mini;
+
+ protected int minj;
+
+ protected BinaryNode top;
+
+ protected int ycount;
+
+ double maxheight;
+
+ /**
+ * Calculates and returns r, whatever that is
+ *
+ * @param i
+ * @param j
+ *
+ * @return
+ */
+ protected double findr(int i, int j)
+ {
+ double tmp = 1;
+
+ for (int k = 0; k < noseqs; k++)
+ {
+ if ((k != i) && (k != j) && (!done.get(k)))
+ {
+ tmp = tmp + distances.getValue(i, k);
+ }
+ }
+
+ if (noClus > 2)
+ {
+ tmp = tmp / (noClus - 2);
+ }
+
+ return tmp;
+ }
+
+ /**
+ * Merges cluster(j) to cluster(i) and recalculates cluster and node distances
+ *
+ * @param i
+ * @param j
+ */
+ protected void joinClusters(final int i, final int j)
+ {
+ double dist = distances.getValue(i, j);
+
+ ri = findr(i, j);
+ rj = findr(j, i);
+
+ findClusterDistance(i, j);
+
+ BinaryNode sn = new BinaryNode();
+
+ sn.setLeft((node.elementAt(i)));
+ sn.setRight((node.elementAt(j)));
+
+ BinaryNode tmpi = (node.elementAt(i));
+ BinaryNode tmpj = (node.elementAt(j));
+
+ findNewDistances(tmpi, tmpj, dist);
+
+ tmpi.setParent(sn);
+ tmpj.setParent(sn);
+
+ node.setElementAt(sn, i);
+
+ /*
+ * move the members of cluster(j) to cluster(i)
+ * and mark cluster j as out of the game
+ */
+ clusters.get(i).or(clusters.get(j));
+ clusters.get(j).clear();
+ done.set(j);
+ }
+
+ protected abstract void findNewDistances(BinaryNode nodei,
+ BinaryNode nodej, double previousDistance);
+
+ /**
+ * Calculates and saves the distance between the combination of cluster(i) and
+ * cluster(j) and all other clusters. The form of the calculation depends on
+ * the tree clustering method being used.
+ *
+ * @param i
+ * @param j
+ */
+ protected abstract void findClusterDistance(int i, int j);
+
+ /**
+ * Finds the node, at or below the given node, with the maximum distance, and
+ * saves the node and the distance value
+ *
+ * @param nd
+ */
+ protected void findMaxDist(BinaryNode nd)
+ {
+ if (nd == null)
+ {
+ return;
+ }
+
+ if ((nd.left() == null) && (nd.right() == null))
+ {
+ double dist = nd.dist;
+
+ if (dist > maxDistValue)
+ {
+ maxdist = nd;
+ maxDistValue = dist;
+ }
+ }
+ else
+ {
+ findMaxDist((BinaryNode) nd.left());
+ findMaxDist((BinaryNode) nd.right());
+ }
+ }
+
+ /**
+ * Form clusters by grouping sub-clusters, starting from one sequence per
+ * cluster, and finishing when only two clusters remain
+ */
+ protected void cluster()
+ {
+ while (noClus > 2)
+ {
+ findMinDistance();
+
+ joinClusters(mini, minj);
+
+ noClus--;
+ }
+
+ int rightChild = done.nextClearBit(0);
+ int leftChild = done.nextClearBit(rightChild + 1);
+
+ joinClusters(leftChild, rightChild);
+ top = (node.elementAt(leftChild));
+
+ reCount(top);
+ findHeight(top);
+ findMaxDist(top);
+ }
+
+ /**
+ * Returns the minimum distance between two clusters, and also sets the
+ * indices of the clusters in fields mini and minj
+ *
+ * @return
+ */
+ protected abstract double findMinDistance();
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param nd
+ * DOCUMENT ME!
+ */
+ protected void _reCount(BinaryNode nd)
+ {
+ // if (_lycount<_lylimit)
+ // {
+ // System.err.println("Warning: depth of _recount greater than number of
+ // nodes.");
+ // }
+ if (nd == null)
+ {
+ return;
+ }
+ // _lycount++;
+
+ if ((nd.left() != null) && (nd.right() != null))
+ {
+
+ _reCount(nd.left());
+ _reCount((BinaryNode) nd.right());
+
+ BinaryNode l = nd.left();
+ BinaryNode r = nd.right();
+
+ nd.count = l.count + r.count;
+ nd.ycount = (l.ycount + r.ycount) / 2;
+ }
+ else
+ {
+ nd.count = 1;
+ nd.ycount = ycount++;
+ }
+ // _lycount--;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param nd
+ * DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ double findHeight(BinaryNode nd)
+ {
+ if (nd == null)
+ {
+ return maxheight;
+ }
+
+ if ((nd.left() == null) && (nd.right() == null))
+ {
+ nd.height = ((BinaryNode) nd.parent()).height + nd.dist;
+
+ if (nd.height > maxheight)
+ {
+ return nd.height;
+ }
+ else
+ {
+ return maxheight;
+ }
+ }
+ else
+ {
+ if (nd.parent() != null)
+ {
+ nd.height = ((BinaryNode) nd.parent()).height + nd.dist;
+ }
+ else
+ {
+ maxheight = 0;
+ nd.height = (float) 0.0;
+ }
+
+ maxheight = findHeight((BinaryNode) (nd.left()));
+ maxheight = findHeight((BinaryNode) (nd.right()));
+ }
+
+ return maxheight;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param nd
+ * DOCUMENT ME!
+ */
+ void reCount(BinaryNode nd)
+ {
+ ycount = 0;
+ // _lycount = 0;
+ // _lylimit = this.node.size();
+ _reCount(nd);
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ public BinaryNode getTopNode()
+ {
+ return top;
+ }
+
+}
*/
package jalview.analysis;
-import jalview.bin.Cache;
import jalview.datamodel.AlignmentView;
import jalview.datamodel.BinaryNode;
import jalview.datamodel.NodeTransformI;
int noseqs;
- SequenceNode top;
+ BinaryNode top;
double maxDistValue;
int ycount;
- Vector<SequenceNode> node;
+ Vector<BinaryNode> node;
boolean hasDistances = true; // normal case for jalview trees
public TreeModel(SequenceI[] seqs, AlignmentView odata,
NewickFile treefile)
{
- this(seqs, treefile.getTree(), treefile.HasDistances(),
+ this(seqs, treefile.getTree(), treefile.HasDistances(),
treefile.HasBootstrap(), treefile.HasRootDistance());
seqData = odata;
*/
public TreeModel(TreeBuilder tree)
{
- this(tree.getSequences(), tree.getTopNode(), tree.hasDistances(),
+ this(tree.getSequences(), tree.getTopNode(), tree.hasDistances(),
tree.hasBootstrap(), tree.hasRootDistance());
seqData = tree.getOriginalData();
}
* @param hasBoot
* @param hasRootDist
*/
- public TreeModel(SequenceI[] seqs, SequenceNode root, boolean hasDist,
+ public TreeModel(SequenceI[] seqs, BinaryNode root, boolean hasDist,
boolean hasBoot, boolean hasRootDist)
{
this.sequences = seqs;
{
SequenceIdMatcher algnIds = new SequenceIdMatcher(seqs);
- Vector<SequenceNode> leaves = findLeaves(top);
+ Vector<BinaryNode> leaves = findLeaves(top);
int i = 0;
int namesleft = seqs.length;
// int countOne2Many = 0;
while (i < leaves.size())
{
- j = leaves.elementAt(i++);
+ // TODO - decide if we get rid of the polymorphism here ?
+ j = (SequenceNode)leaves.elementAt(i++);
realnam = j.getName();
nam = null;
*/
public void updatePlaceHolders(List<SequenceI> list)
{
- Vector<SequenceNode> leaves = findLeaves(top);
+ Vector<BinaryNode> leaves = findLeaves(top);
int sz = leaves.size();
SequenceIdMatcher seqmatcher = null;
while (i < sz)
{
- SequenceNode leaf = leaves.elementAt(i++);
+ SequenceNode leaf = (SequenceNode) leaves.elementAt(i++);
if (list.contains(leaf.element()))
{
/**
* Search for leaf nodes below (or at) the given node
*
- * @param nd
+ * @param top2
* root node to search from
*
* @return
*/
- public Vector<SequenceNode> findLeaves(SequenceNode nd)
+ public Vector<BinaryNode> findLeaves(BinaryNode top2)
{
- Vector<SequenceNode> leaves = new Vector<SequenceNode>();
- findLeaves(nd, leaves);
+ Vector<BinaryNode> leaves = new Vector<BinaryNode>();
+ findLeaves(top2, leaves);
return leaves;
}
*
* @return Vector of leaf nodes on binary tree
*/
- Vector<SequenceNode> findLeaves(SequenceNode nd,
- Vector<SequenceNode> leaves)
+ Vector<BinaryNode> findLeaves(BinaryNode nd,
+ Vector<BinaryNode> leaves)
{
if (nd == null)
{
* TODO: Identify internal nodes... if (node.isSequenceLabel()) {
* leaves.addElement(node); }
*/
- findLeaves((SequenceNode) nd.left(), leaves);
- findLeaves((SequenceNode) nd.right(), leaves);
+ findLeaves(nd.left(), leaves);
+ findLeaves(nd.right(), leaves);
}
return leaves;
* @param nd
* SequenceNode
*/
- void printNode(SequenceNode nd)
+ void printNode(BinaryNode nd)
{
if (nd == null)
{
else
{
System.out.println("Dist " + nd.dist);
- printNode((SequenceNode) nd.left());
- printNode((SequenceNode) nd.right());
+ printNode((BinaryNode) nd.left());
+ printNode((BinaryNode) nd.right());
}
}
* @param threshold
* @see #getGroups()
*/
- public List<SequenceNode> groupNodes(float threshold)
+ public List<BinaryNode> groupNodes(float threshold)
{
- List<SequenceNode> groups = new ArrayList<SequenceNode>();
+ List<BinaryNode> groups = new ArrayList<BinaryNode>();
_groupNodes(groups, getTopNode(), threshold);
return groups;
}
- protected void _groupNodes(List<SequenceNode> groups, SequenceNode nd,
+ protected void _groupNodes(List<BinaryNode> groups, BinaryNode nd,
float threshold)
{
if (nd == null)
*
* @return DOCUMENT ME!
*/
- public double findHeight(SequenceNode nd)
+ public double findHeight(BinaryNode nd)
{
if (nd == null)
{
if ((nd.left() == null) && (nd.right() == null))
{
- nd.height = ((SequenceNode) nd.parent()).height + nd.dist;
+ nd.height = ((BinaryNode) nd.parent()).height + nd.dist;
if (nd.height > maxheight)
{
{
if (nd.parent() != null)
{
- nd.height = ((SequenceNode) nd.parent()).height + nd.dist;
+ nd.height = ((BinaryNode) nd.parent()).height + nd.dist;
}
else
{
nd.height = (float) 0.0;
}
- maxheight = findHeight((SequenceNode) (nd.left()));
- maxheight = findHeight((SequenceNode) (nd.right()));
+ maxheight = findHeight((BinaryNode) (nd.left()));
+ maxheight = findHeight((BinaryNode) (nd.right()));
}
return maxheight;
* @param nd
* DOCUMENT ME!
*/
- void printN(SequenceNode nd)
+ void printN(BinaryNode nd)
{
if (nd == null)
{
if ((nd.left() != null) && (nd.right() != null))
{
- printN((SequenceNode) nd.left());
- printN((SequenceNode) nd.right());
+ printN((BinaryNode) nd.left());
+ printN((BinaryNode) nd.right());
}
else
{
* @param nd
* DOCUMENT ME!
*/
- public void reCount(SequenceNode nd)
+ public void reCount(BinaryNode nd)
{
ycount = 0;
// _lycount = 0;
* @param nd
* DOCUMENT ME!
*/
- void _reCount(SequenceNode nd)
+ void _reCount(BinaryNode nd)
{
// if (_lycount<_lylimit)
// {
if ((nd.left() != null) && (nd.right() != null))
{
- _reCount((SequenceNode) nd.left());
- _reCount((SequenceNode) nd.right());
+ _reCount((BinaryNode) nd.left());
+ _reCount((BinaryNode) nd.right());
- SequenceNode l = (SequenceNode) nd.left();
- SequenceNode r = (SequenceNode) nd.right();
+ BinaryNode l = (BinaryNode) nd.left();
+ BinaryNode r = (BinaryNode) nd.right();
nd.count = l.count + r.count;
nd.ycount = (l.ycount + r.ycount) / 2;
* @param nd
* DOCUMENT ME!
*/
- public void swapNodes(SequenceNode nd)
+ public void swapNodes(BinaryNode nd)
{
if (nd == null)
{
return;
}
- SequenceNode tmp = (SequenceNode) nd.left();
+ BinaryNode tmp = (BinaryNode) nd.left();
nd.setLeft(nd.right());
nd.setRight(tmp);
* @param dir
* DOCUMENT ME!
*/
- void changeDirection(SequenceNode nd, SequenceNode dir)
+ void changeDirection(BinaryNode nd, BinaryNode dir)
{
if (nd == null)
{
if (nd.parent() != top)
{
- changeDirection((SequenceNode) nd.parent(), nd);
+ changeDirection((BinaryNode) nd.parent(), nd);
- SequenceNode tmp = (SequenceNode) nd.parent();
+ BinaryNode tmp = (BinaryNode) nd.parent();
if (dir == nd.left())
{
*
* @return DOCUMENT ME!
*/
- public SequenceNode getTopNode()
+ public BinaryNode getTopNode()
{
return top;
}
*/
public void applyToNodes(NodeTransformI nodeTransformI)
{
- for (Enumeration<SequenceNode> nodes = node.elements(); nodes
+ for (Enumeration<BinaryNode> nodes = node.elements(); nodes
.hasMoreElements(); nodeTransformI
.transform(nodes.nextElement()))
{
import jalview.datamodel.AlignmentView;
import jalview.datamodel.ColumnSelection;
import jalview.datamodel.ContactListI;
+import jalview.datamodel.ContactMatrixI;
import jalview.datamodel.ProfilesI;
import jalview.datamodel.SearchResultsI;
import jalview.datamodel.SequenceCollectionI;
* @return
*/
Iterator<int[]> getViewAsVisibleContigs(boolean selectedRegionOnly);
+
+ ContactMatrixI getContactMatrix(AlignmentAnnotation alignmentAnnotation);
}
import jalview.analysis.Conservation;
import jalview.analysis.TreeModel;
import jalview.api.AlignViewportI;
+import jalview.datamodel.BinaryNode;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
Hashtable nodeHash = new Hashtable();
- SequenceNode highlightNode;
+ BinaryNode highlightNode;
AlignmentPanel ap;
tree2.findHeight(tree2.getTopNode());
// Now have to calculate longest name based on the leaves
- Vector<SequenceNode> leaves = tree2.findLeaves(tree2.getTopNode());
+ Vector<BinaryNode> leaves = tree2.findLeaves(tree2.getTopNode());
boolean has_placeholders = false;
longestName = "";
for (int i = 0; i < leaves.size(); i++)
{
- SequenceNode lf = leaves.elementAt(i);
+ BinaryNode lf = leaves.elementAt(i);
- if (lf.isPlaceholder())
+ if (lf instanceof SequenceNode && ((SequenceNode)lf).isPlaceholder())
{
has_placeholders = true;
}
setMarkPlaceholders(has_placeholders);
}
- public void drawNode(Graphics g, SequenceNode node, float chunk,
+ public void drawNode(Graphics g, BinaryNode node, float chunk,
double scale, int width, int offx, int offy)
{
if (node == null)
g.drawString(nodeLabel, xstart + 2, ypos - 2);
}
- String name = (markPlaceholders && node.isPlaceholder())
+ String name = (markPlaceholders && node instanceof SequenceNode && ((SequenceNode) node).isPlaceholder())
? (PLACEHOLDER + node.getName())
: node.getName();
FontMetrics fm = g.getFontMetrics(font);
}
else
{
- drawNode(g, (SequenceNode) node.left(), chunk, scale, width, offx,
+ drawNode(g, (BinaryNode) node.left(), chunk, scale, width, offx,
offy);
- drawNode(g, (SequenceNode) node.right(), chunk, scale, width, offx,
+ drawNode(g, (BinaryNode) node.right(), chunk, scale, width, offx,
offy);
double height = node.height;
}
int ystart = (int) (node.left() == null ? 0
- : (((SequenceNode) node.left()).ycount * chunk)) + offy;
+ : (((BinaryNode) node.left()).ycount * chunk)) + offy;
int yend = (int) (node.right() == null ? 0
- : (((SequenceNode) node.right()).ycount * chunk)) + offy;
+ : (((BinaryNode) node.right()).ycount * chunk)) + offy;
Rectangle pos = new Rectangle(xend - 2, ypos - 2, 5, 5);
nodeHash.put(node, pos);
int width = getSize().width;
int height = getSize().height;
- SequenceNode top = tree.getTopNode();
+ BinaryNode top = tree.getTopNode();
double wscale = (float) (width * .8 - offx * 2) / tree.getMaxHeight();
if (top.count == 0)
{
- top.count = ((SequenceNode) top.left()).count
- + ((SequenceNode) top.right()).count;
+ top.count = ((BinaryNode) top.left()).count
+ + ((BinaryNode) top.right()).count;
}
float chunk = (float) (height - offy) / top.count;
pickNode(pickBox, top, chunk, wscale, width, offx, offy);
}
- public void pickNode(Rectangle pickBox, SequenceNode node, float chunk,
+ public void pickNode(Rectangle pickBox, BinaryNode node, float chunk,
double scale, int width, int offx, int offy)
{
if (node == null)
}
else
{
- pickNode(pickBox, (SequenceNode) node.left(), chunk, scale, width,
+ pickNode(pickBox, (BinaryNode) node.left(), chunk, scale, width,
offx, offy);
- pickNode(pickBox, (SequenceNode) node.right(), chunk, scale, width,
+ pickNode(pickBox, (BinaryNode) node.right(), chunk, scale, width,
offx, offy);
}
}
- public void setColor(SequenceNode node, Color c)
+ public void setColor(BinaryNode node, Color c)
{
if (node == null)
{
else
{
node.color = c;
- setColor((SequenceNode) node.left(), c);
- setColor((SequenceNode) node.right(), c);
+ setColor((BinaryNode) node.left(), c);
+ setColor((BinaryNode) node.right(), c);
}
}
double wscale = (width - labelLength - offx * 2) / tree.getMaxHeight();
- SequenceNode top = tree.getTopNode();
+ BinaryNode top = tree.getTopNode();
if (top.count == 0)
{
- top.count = ((SequenceNode) top.left()).count
- + ((SequenceNode) top.right()).count;
+ top.count = ((BinaryNode) top.left()).count
+ + ((BinaryNode) top.right()).count;
}
float chunk = (float) (height - offy) / top.count;
}
else
{
- Vector<SequenceNode> leaves = tree.findLeaves(highlightNode);
+ Vector<BinaryNode> leaves = tree.findLeaves(highlightNode);
for (int i = 0; i < leaves.size(); i++)
{
Object ob = findElement(evt.getX(), evt.getY());
- if (ob instanceof SequenceNode)
+ if (ob instanceof BinaryNode)
{
- highlightNode = (SequenceNode) ob;
+ highlightNode = (BinaryNode) ob;
repaint();
}
else
threshold = (float) (x - offx)
/ (float) (getSize().width - labelLength - 2 * offx);
- List<SequenceNode> groups = tree.groupNodes(threshold);
+ List<BinaryNode> groups = tree.groupNodes(threshold);
setColor(tree.getTopNode(), Color.black);
av.setSelectionGroup(null);
}
- void colourGroups(List<SequenceNode> groups)
+ void colourGroups(List<BinaryNode> groups)
{
for (int i = 0; i < groups.size(); i++)
{
(int) (Math.random() * 255), (int) (Math.random() * 255));
setColor(groups.get(i), col.brighter());
- Vector<SequenceNode> l = tree.findLeaves(groups.get(i));
+ Vector<BinaryNode> l = tree.findLeaves(groups.get(i));
Vector<SequenceI> sequences = new Vector<>();
for (int j = 0; j < l.size(); j++)
}
@Override
- public ContactMatrixI getContactMatrixFor(AlignmentAnnotation ann)
+ public ContactMatrixI getContactMatrixFor(AlignmentAnnotation _aa)
{
- return cmholder.getContactMatrixFor(ann);
+ ContactMatrixI cm = cmholder.getContactMatrixFor(_aa);
+ if (cm==null && _aa.groupRef!=null)
+ {
+ cm = _aa.groupRef.getContactMatrixFor(_aa);
+ }
+ if (cm==null && _aa.sequenceRef!=null)
+ {
+ cm = _aa.sequenceRef.getContactMatrixFor(_aa);
+ if (cm==null)
+ {
+ // TODO fix up this logic and unify with getContactListFor
+ cm = _aa.sequenceRef.getDatasetSequence().getContactMatrixFor(_aa);
+ }
+ }
+ return cm;
}
@Override
*/
package jalview.datamodel;
+import java.awt.Color;
+
/**
* DOCUMENT ME!
*
BinaryNode parent;
- /** DOCUMENT ME!! */
+ /** Bootstrap value */
public int bootstrap;
+ /** DOCUMENT ME!! */
+ public double dist;
+
+ /** DOCUMENT ME!! */
+ public int count;
+
+ /** DOCUMENT ME!! */
+ public double height;
+
+ /** DOCUMENT ME!! */
+ public float ycount;
+
+ /** DOCUMENT ME!! */
+ public Color color = Color.black;
+
+ /** DOCUMENT ME!! */
+ public boolean dummy = false;
+
/**
* Creates a new BinaryNode object.
*/
{
left = right = parent = null;
bootstrap = 0;
+ dist = 0;
}
/**
* @param name
* DOCUMENT ME!
*/
- public BinaryNode(Object element, BinaryNode parent, String name)
+ public BinaryNode(Object element, BinaryNode parent, String name,
+ double dist)
{
+ this();
this.element = element;
this.parent = parent;
this.name = name;
+ this.dist = dist;
+ }
+
+ public BinaryNode(Object element, BinaryNode parent, String name,
+ double dist, int bootstrap)
+ {
+ this(element, parent, name, dist);
+ this.bootstrap = bootstrap;
+ }
- left = right = null;
+ public BinaryNode(Object val, BinaryNode parent, String name, double dist,
+ int bootstrap, boolean dummy)
+ {
+ this(val, parent, name, dist, bootstrap);
+ this.dummy = dummy;
}
/**
{
return bootstrap;
}
+
+ /**
+ * @param dummy
+ * true if node is created for the representation of polytomous trees
+ */
+ public boolean isDummy()
+ {
+ return dummy;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param newstate
+ * DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ public boolean setDummy(boolean newstate)
+ {
+ boolean oldstate = dummy;
+ dummy = newstate;
+
+ return oldstate;
+ }
+
+ /**
+ * ascends the tree but doesn't stop until a non-dummy node is discovered.
+ *
+ */
+ public BinaryNode AscendTree()
+ {
+ BinaryNode c = this;
+
+ do
+ {
+ c = c.parent();
+ } while ((c != null) && c.dummy);
+
+ return c;
+ }
}
@Override
public ContactRange getRangeFor(int from_column, int to_column)
{
+ // TODO: consider caching ContactRange for a particular call ?
if (clist instanceof ContactListI)
{
// clist may implement getRangeFor in a more efficient way, so use theirs
package jalview.datamodel;
+import java.util.BitSet;
+
public interface ContactMatrixI
{
int getWidth();
int getHeight();
+
+ default boolean hasGroups() {
+ return false;
+ }
+ default BitSet getGroupsFor(int column) {
+ BitSet colbitset = new BitSet();
+ colbitset.set(column);
+ return colbitset;
+ }
}
*/
package jalview.datamodel;
-import java.awt.Color;
-
/**
* DOCUMENT ME!
*
*/
public class SequenceNode extends BinaryNode
{
- /** DOCUMENT ME!! */
- public double dist;
-
- /** DOCUMENT ME!! */
- public int count;
-
- /** DOCUMENT ME!! */
- public double height;
-
- /** DOCUMENT ME!! */
- public float ycount;
-
- /** DOCUMENT ME!! */
- public Color color = Color.black;
-
- /** DOCUMENT ME!! */
- public boolean dummy = false;
-
private boolean placeholder = false;
/**
super();
}
- /**
- * Creates a new SequenceNode object.
- *
- * @param val
- * DOCUMENT ME!
- * @param parent
- * DOCUMENT ME!
- * @param dist
- * DOCUMENT ME!
- * @param name
- * DOCUMENT ME!
- */
- public SequenceNode(Object val, SequenceNode parent, double dist,
- String name)
+ public SequenceNode(SequenceI val, BinaryNode parent, String name,
+ double dist, int bootstrap, boolean dummy)
{
- super(val, parent, name);
- this.dist = dist;
+ super(val, parent, name, dist, bootstrap, dummy);
}
- /**
- * Creates a new SequenceNode object.
- *
- * @param val
- * DOCUMENT ME!
- * @param parent
- * DOCUMENT ME!
- * @param name
- * DOCUMENT ME!
- * @param dist
- * DOCUMENT ME!
- * @param bootstrap
- * DOCUMENT ME!
- * @param dummy
- * DOCUMENT ME!
- */
- public SequenceNode(Object val, SequenceNode parent, String name,
- double dist, int bootstrap, boolean dummy)
+ public SequenceNode(SequenceI element, BinaryNode parent, String name,
+ double dist, int bootstrap)
{
- super(val, parent, name);
- this.dist = dist;
- this.bootstrap = bootstrap;
- this.dummy = dummy;
+ super(element, parent, name, dist, bootstrap);
}
- /**
- * @param dummy
- * true if node is created for the representation of polytomous trees
- */
- public boolean isDummy()
+ public SequenceNode(SequenceI element, BinaryNode parent, String name,
+ double dist)
{
- return dummy;
+ super(element, parent, name, dist);
}
/*
/**
* DOCUMENT ME!
*
- * @param newstate
- * DOCUMENT ME!
- *
- * @return DOCUMENT ME!
- */
- public boolean setDummy(boolean newstate)
- {
- boolean oldstate = dummy;
- dummy = newstate;
-
- return oldstate;
- }
-
- /**
- * DOCUMENT ME!
- *
* @param Placeholder
* DOCUMENT ME!
*/
}
/**
- * ascends the tree but doesn't stop until a non-dummy node is discovered.
- * This will probably break if the tree is a mixture of BinaryNodes and
- * SequenceNodes.
- */
- public SequenceNode AscendTree()
- {
- SequenceNode c = this;
-
- do
- {
- c = (SequenceNode) c.parent();
- } while ((c != null) && c.dummy);
-
- return c;
- }
-
- /**
* test if this node has a name that might be a label rather than a bootstrap
* value
*
import jalview.viewmodel.ViewportRanges;
import jalview.ws.DBRefFetcher;
import jalview.ws.DBRefFetcher.FetchFinishedListenerI;
+import jalview.ws.datamodel.alphafold.PAEContactMatrix;
import jalview.ws.jws1.Discoverer;
import jalview.ws.jws2.Jws2Discoverer;
import jalview.ws.jws2.jabaws2.Jws2Instance;
return showNewickTree(nf, treeTitle, null, w, h, x, y);
}
+
/**
* Add a treeviewer for the tree extracted from a Newick file object to the
* current alignment view
return tp;
}
+
+ public void showContactMapTree(AlignmentAnnotation aa,
+ PAEContactMatrix cm)
+ {
+ int x = 4, y = 5;
+ int w = 400, h = 500;
+ try
+ {
+ NewickFile fin = new NewickFile(
+ new FileParse(cm.getNewickString(), DataSourceType.PASTE));
+ fin.parse();
+ if (fin.getTree() == null)
+ {
+ return;
+ }
+ String title = "PAE Matrix Tree for "
+ + cm.getReferenceSeq().getDisplayId(false);
+ TreePanel tp = new TreePanel(alignPanel, fin, aa, title);
+
+ tp.setSize(w, h);
+
+ if (x > 0 && y > 0)
+ {
+ tp.setLocation(x, y);
+ }
+
+ Desktop.addInternalFrame(tp, title, w, h);
+ } catch (Throwable xx)
+ {
+ Console.error("Unexpected exception showing tree for contact matrix",
+ xx);
+ }
+
+ }
private boolean buildingMenu = false;
/**
{
return lastFeatureSettingsBounds;
}
+
}
class PrintThread extends Thread
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.AffineTransform;
+import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import jalview.analysis.AlignSeq;
import jalview.analysis.AlignmentUtils;
+import jalview.bin.Console;
import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.Annotation;
+import jalview.datamodel.ContactMatrixI;
import jalview.datamodel.HiddenColumns;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
+import jalview.io.DataSourceType;
import jalview.io.FileFormat;
import jalview.io.FormatAdapter;
+import jalview.io.NewickFile;
import jalview.util.Comparison;
import jalview.util.MessageManager;
import jalview.util.Platform;
+import jalview.ws.datamodel.alphafold.PAEContactMatrix;
/**
* The panel that holds the labels for alignment annotations, providing
consclipbrd.addActionListener(this);
pop.add(consclipbrd);
}
+ if (aa[selectedRow].graph == AlignmentAnnotation.CONTACT_MAP
+ && PAEContactMatrix.PAEMATRIX
+ .equals(aa[selectedRow].getCalcId()))
+ {
+ final PAEContactMatrix cm = (PAEContactMatrix) av
+ .getContactMatrix(aa[selectedRow]);
+ if (cm.getNewickString()!=null && cm.getNewickString().length()>0)
+ {
+ item = new JMenuItem("Show Matrix");
+ item.addActionListener(new ActionListener()
+ {
+
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+
+ ap.alignFrame.showContactMapTree(aa[selectedRow],cm);
+
+ }
+ });
+ pop.addSeparator();
+ pop.add(item);
+ }
+
+ }
}
pop.show(this, evt.getX(), evt.getY());
}
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.util.ArrayList;
+import java.util.BitSet;
import java.util.Collections;
import java.util.List;
import jalview.datamodel.Annotation;
import jalview.datamodel.ColumnSelection;
import jalview.datamodel.ContactListI;
+import jalview.datamodel.ContactMatrixI;
import jalview.datamodel.ContactRange;
import jalview.datamodel.GraphLine;
import jalview.datamodel.HiddenColumns;
else
{
GraphLine thr = aa[graphStretch].getThreshold();
+
int currentX = getColumnForXPos(evt.getX());
ContactListI forCurrentX = av.getContactList(aa[graphStretch],
currentX);
aa[graphStretch].graphHeight);
ContactGeometry.contactInterval cXci = cXcgeom.mapFor(yOffset,
yOffset);
+ /**
+ * start and end range corresponding to the row range under the
+ * mouse at column currentX
+ */
int fr, to;
fr = Math.min(cXci.cStart, cXci.cEnd);
to = Math.max(cXci.cStart, cXci.cEnd);
- // select corresponding range in segment under mouse
+
+ if (evt.isControlDown())
{
- for (int c = fr; c <= to; c++)
+ ContactMatrixI matrix = av.getContactMatrix(aa[graphStretch]);
+
+ if (matrix != null)
{
- av.getColumnSelection().addElement(c);
+ // simplest approach is to select all group containing column
+ if (matrix.hasGroups())
+ {
+ SequenceI rseq = aa[graphStretch].sequenceRef;
+ BitSet grp = matrix.getGroupsFor(currentX);
+ for (int c=fr;c<=to; c++)
+ {
+ BitSet additionalGrp = matrix.getGroupsFor(c);
+ grp.or(additionalGrp);
+ }
+ HiddenColumns hc = av.getAlignment().getHiddenColumns();
+ for (int p = grp.nextSetBit(0); p >= 0; p = grp
+ .nextSetBit(p + 1))
+ {
+ int offp = (rseq != null)
+ ? rseq.findIndex(rseq.getStart() - 1 + p)
+ : p;
+
+ if (!av.hasHiddenColumns() || hc.isVisible(offp))
+ {
+ av.getColumnSelection().addElement(offp);
+ }
+ }
+ }
+ // possible alternative for interactive selection - threshold
+ // gives 'ceiling' for forming a cluster
+ // when a row+column is selected, farthest common ancestor less
+ // than thr is used to compute cluster
+
}
- av.getColumnSelection().addElement(currentX);
}
- // PAE SPECIFIC
- // and also select everything lower than the max range adjacent
- // (kind of works)
- if (PAEContactMatrix.PAEMATRIX.equals(aa[graphStretch].getCalcId()))
+ else
{
- int c = fr - 1;
- ContactRange cr = forCurrentX.getRangeFor(fr, to);
- double cval;
- // TODO: could use GraphLine instead of arbitrary picking
- // TODO: could report mean/median/variance for partitions (contiguous selected vs unselected regions and inter-contig regions)
- // controls feathering - what other elements in row/column should we select
- double thresh=cr.getMean()+(cr.getMax()-cr.getMean())*.15;
- while (c > 0)
+ // select corresponding range in segment under mouse
{
- cval = forCurrentX.getContactAt(c);
- if (// cr.getMin() <= cval &&
- cval <= thresh)
- {
- av.getColumnSelection().addElement(c--);
- }
- else
+ for (int c = fr; c <= to; c++)
{
- break;
+ av.getColumnSelection().addElement(c);
}
+ av.getColumnSelection().addElement(currentX);
}
- c = to;
- while (c < forCurrentX.getContactHeight())
+ // PAE SPECIFIC
+ // and also select everything lower than the max range adjacent
+ // (kind of works)
+ if (PAEContactMatrix.PAEMATRIX
+ .equals(aa[graphStretch].getCalcId()))
{
- cval = forCurrentX.getContactAt(c);
- if (// cr.getMin() <= cval &&
- cval <= thresh)
+ int c = fr - 1;
+ ContactRange cr = forCurrentX.getRangeFor(fr, to);
+ double cval;
+ // TODO: could use GraphLine instead of arbitrary picking
+ // TODO: could report mean/median/variance for partitions
+ // (contiguous selected vs unselected regions and inter-contig
+ // regions)
+ // controls feathering - what other elements in row/column
+ // should we select
+ double thresh = cr.getMean()
+ + (cr.getMax() - cr.getMean()) * .15;
+ while (c > 0)
{
- av.getColumnSelection().addElement(c++);
+ cval = forCurrentX.getContactAt(c);
+ if (// cr.getMin() <= cval &&
+ cval <= thresh)
+ {
+ av.getColumnSelection().addElement(c--);
+ }
+ else
+ {
+ break;
+ }
}
- else
+ c = to;
+ while (c < forCurrentX.getContactHeight())
{
- break;
+ cval = forCurrentX.getContactAt(c);
+ if (// cr.getMin() <= cval &&
+ cval <= thresh)
+ {
+ av.getColumnSelection().addElement(c++);
+ }
+ else
+ {
+ break;
+ }
}
}
}
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
+import java.util.BitSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import jalview.analysis.Conservation;
import jalview.analysis.TreeModel;
import jalview.api.AlignViewportI;
+import jalview.datamodel.BinaryNode;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
Map<Object, Rectangle> nameHash = new Hashtable<>();
- Map<SequenceNode, Rectangle> nodeHash = new Hashtable<>();
+ Map<BinaryNode, Rectangle> nodeHash = new Hashtable<>();
- SequenceNode highlightNode;
+ BinaryNode highlightNode;
boolean applyToAllViews = false;
tree.findHeight(tree.getTopNode());
// Now have to calculate longest name based on the leaves
- Vector<SequenceNode> leaves = tree.findLeaves(tree.getTopNode());
+ Vector<BinaryNode> leaves = tree.findLeaves(tree.getTopNode());
boolean has_placeholders = false;
longestName = "";
for (int i = 0; i < leaves.size(); i++)
{
- SequenceNode lf = leaves.elementAt(i);
+ BinaryNode lf = leaves.elementAt(i);
- if (lf.isPlaceholder())
+ if (lf instanceof SequenceNode && ((SequenceNode)lf).isPlaceholder())
{
has_placeholders = true;
}
* @param offy
* DOCUMENT ME!
*/
- public void drawNode(Graphics g, SequenceNode node, float chunk,
+ public void drawNode(Graphics g, BinaryNode node, float chunk,
double wscale, int width, int offx, int offy)
{
if (node == null)
g.drawString(nodeLabel, xstart + 2, ypos - 2);
}
- String name = (markPlaceholders && node.isPlaceholder())
+ String name = (markPlaceholders && ((node instanceof SequenceNode && ((SequenceNode)node).isPlaceholder())))
? (PLACEHOLDER + node.getName())
: node.getName();
nameHash.put(node.element(), rect);
// Colour selected leaves differently
- SequenceGroup selected = av.getSelectionGroup();
+ boolean isSelected = false;
+ if (tp.getColumnWise())
+ {
+ isSelected = isColumnForNodeSelected(node);
+ }
+ else
+ {
+ SequenceGroup selected = av.getSelectionGroup();
- if ((selected != null)
- && selected.getSequences(null).contains(node.element()))
+ if ((selected != null)
+ && selected.getSequences(null).contains(node.element()))
+ {
+ isSelected = true;
+ }
+ }
+ if (isSelected)
{
g.setColor(Color.gray);
}
else
{
- drawNode(g, (SequenceNode) node.left(), chunk, wscale, width, offx,
+ drawNode(g, (BinaryNode) node.left(), chunk, wscale, width, offx,
offy);
- drawNode(g, (SequenceNode) node.right(), chunk, wscale, width, offx,
+ drawNode(g, (BinaryNode) node.right(), chunk, wscale, width, offx,
offy);
double height = node.height;
}
int ystart = (node.left() == null ? 0
- : (int) (((SequenceNode) node.left()).ycount * chunk)) + offy;
+ : (int) (((BinaryNode) node.left()).ycount * chunk)) + offy;
int yend = (node.right() == null ? 0
- : (int) (((SequenceNode) node.right()).ycount * chunk))
+ : (int) (((BinaryNode) node.right()).ycount * chunk))
+ offy;
Rectangle pos = new Rectangle(xend - 2, ypos - 2, 5, 5);
}
}
- for (Entry<SequenceNode, Rectangle> entry : nodeHash.entrySet())
+ for (Entry<BinaryNode, Rectangle> entry : nodeHash.entrySet())
{
Rectangle rect = entry.getValue();
int width = getWidth();
int height = getHeight();
- SequenceNode top = tree.getTopNode();
+ BinaryNode top = tree.getTopNode();
double wscale = ((width * .8) - (offx * 2)) / tree.getMaxHeight();
if (top.count == 0)
{
- top.count = ((SequenceNode) top.left()).count
- + ((SequenceNode) top.right()).count;
+ top.count = ((BinaryNode) top.left()).count
+ + ((BinaryNode) top.right()).count;
}
float chunk = (float) (height - (offy)) / top.count;
* @param offy
* DOCUMENT ME!
*/
- public void pickNode(Rectangle pickBox, SequenceNode node, float chunk,
+ public void pickNode(Rectangle pickBox, BinaryNode node, float chunk,
double wscale, int width, int offx, int offy)
{
if (node == null)
}
else
{
- pickNode(pickBox, (SequenceNode) node.left(), chunk, wscale, width,
+ pickNode(pickBox, (BinaryNode) node.left(), chunk, wscale, width,
offx, offy);
- pickNode(pickBox, (SequenceNode) node.right(), chunk, wscale, width,
+ pickNode(pickBox, (BinaryNode) node.right(), chunk, wscale, width,
offx, offy);
}
}
* @param c
* DOCUMENT ME!
*/
- public void setColor(SequenceNode node, Color c)
+ public void setColor(BinaryNode node, Color c)
{
if (node == null)
{
}
}
}
- setColor((SequenceNode) node.left(), c);
- setColor((SequenceNode) node.right(), c);
+ setColor((BinaryNode) node.left(), c);
+ setColor((BinaryNode) node.right(), c);
}
/**
if (longestName == null || tree == null)
{
g2.drawString("Calculating tree.", 20, 20);
+ return;
}
offy = font.getSize() + 10;
double wscale = (width - labelLength - (offx * 2))
/ tree.getMaxHeight();
- SequenceNode top = tree.getTopNode();
+ BinaryNode top = tree.getTopNode();
if (top.count == 0)
{
- top.count = ((SequenceNode) top.left()).count
- + ((SequenceNode) top.right()).count;
+ top.count = ((BinaryNode) top.left()).count
+ + ((BinaryNode) top.right()).count;
}
float chunk = (float) (height - (offy)) / top.count;
}
else
{
- Vector<SequenceNode> leaves = tree.findLeaves(highlightNode);
-
+ Vector<BinaryNode> leaves = tree.findLeaves(highlightNode);
+ if (tp.getColumnWise()) {
+ markColumnsFor(getAssociatedPanels(), leaves, Color.red);
+ } else {
for (int i = 0; i < leaves.size(); i++)
{
SequenceI seq = (SequenceI) leaves.elementAt(i).element();
treeSelectionChanged(seq);
}
+ }
av.sendSelection();
}
Object ob = findElement(evt.getX(), evt.getY());
- if (ob instanceof SequenceNode)
+ if (ob instanceof BinaryNode)
{
- highlightNode = (SequenceNode) ob;
+ highlightNode = (BinaryNode) ob;
this.setToolTipText(
"<html>" + MessageManager.getString("label.highlightnode"));
repaint();
av.sendSelection();
return;
}
- else if (!(ob instanceof SequenceNode))
+ else if (!(ob instanceof BinaryNode))
{
// Find threshold
if (tree.getMaxHeight() != 0)
threshold = (float) (x - offx)
/ (float) (getWidth() - labelLength - (2 * offx));
- List<SequenceNode> groups = tree.groupNodes(threshold);
+ List<BinaryNode> groups = tree.groupNodes(threshold);
setColor(tree.getTopNode(), Color.black);
AlignmentPanel[] aps = getAssociatedPanels();
}
- void colourGroups(List<SequenceNode> groups)
+ void colourGroups(List<BinaryNode> groups)
{
AlignmentPanel[] aps = getAssociatedPanels();
for (int i = 0; i < groups.size(); i++)
(int) (Math.random() * 255), (int) (Math.random() * 255));
setColor(groups.get(i), col.brighter());
- Vector<SequenceNode> l = tree.findLeaves(groups.get(i));
-
- Vector<SequenceI> sequences = new Vector<>();
+ Vector<BinaryNode> l = tree.findLeaves(groups.get(i));
+ if (!tp.getColumnWise()) {
+ createSeqGroupFor(aps, l, col);
+ } else {
+ markColumnsFor(aps,l,col);
+ }
+ }
- for (int j = 0; j < l.size(); j++)
+ // notify the panel(s) to redo any group specific stuff
+ // also updates structure views if necessary
+ for (int a = 0; a < aps.length; a++)
+ {
+ aps[a].updateAnnotation();
+ final AlignViewportI codingComplement = aps[a].av
+ .getCodingComplement();
+ if (codingComplement != null)
{
- SequenceI s1 = (SequenceI) l.elementAt(j).element();
-
- if (!sequences.contains(s1))
- {
- sequences.addElement(s1);
- }
+ ((AlignViewport) codingComplement).getAlignPanel()
+ .updateAnnotation();
}
+ }
+ }
- ColourSchemeI cs = null;
- SequenceGroup _sg = new SequenceGroup(sequences, null, cs, true, true,
- false, 0, av.getAlignment().getWidth() - 1);
+ private boolean isColumnForNodeSelected(BinaryNode bn)
+ {
+ SequenceI rseq = tp.assocAnnotation.sequenceRef;
+ int colm = -1;
+ try
+ {
+ colm = Integer.parseInt(
+ bn.getName().substring(bn.getName().indexOf("c") + 1));
+ } catch (Exception e)
+ {
+ return false;
+ }
+ ColumnSelection cs = av.getColumnSelection();
+ HiddenColumns hc = av.getAlignment().getHiddenColumns();
+ int offp = (rseq != null) ? rseq.findIndex(rseq.getStart() - 1 + colm)
+ : colm;
- _sg.setName("JTreeGroup:" + _sg.hashCode());
- _sg.setIdColour(col);
+ if (!av.hasHiddenColumns() || hc.isVisible(offp))
+ {
+ return cs.contains(offp);
+ }
+ return false;
+ }
- for (int a = 0; a < aps.length; a++)
+ private void markColumnsFor(AlignmentPanel[] aps, Vector<BinaryNode> l,
+ Color col)
+ {
+ SequenceI rseq = tp.assocAnnotation.sequenceRef;
+ for (BinaryNode bn:l)
+ {
+ int colm=-1;
+ try {
+ colm = Integer.parseInt(bn.getName().substring(bn.getName().indexOf("c")+1));
+ } catch (Exception e)
{
- SequenceGroup sg = new SequenceGroup(_sg);
- AlignViewport viewport = aps[a].av;
-
- // Propagate group colours in each view
- if (viewport.getGlobalColourScheme() != null)
- {
- cs = viewport.getGlobalColourScheme().getInstance(viewport, sg);
- sg.setColourScheme(cs);
- sg.getGroupColourScheme().setThreshold(
- viewport.getResidueShading().getThreshold(),
- viewport.isIgnoreGapsConsensus());
-
- if (viewport.getResidueShading().conservationApplied())
+ continue;
+ }
+ ColumnSelection cs = av.getColumnSelection();
+ HiddenColumns hc = av.getAlignment().getHiddenColumns();
+ {
+ int offp = (rseq!=null) ? rseq.findIndex(rseq.getStart()-1+colm) : colm;
+
+ if (!av.hasHiddenColumns() || hc.isVisible(offp))
+ {
+ if (cs.contains(offp))
{
- Conservation c = new Conservation("Group",
- sg.getSequences(null), sg.getStartRes(),
- sg.getEndRes());
- c.calculate();
- c.verdict(false, viewport.getConsPercGaps());
- sg.cs.setConservation(c);
+ cs.removeElement(offp);
+ } else {
+ cs.addElement(offp);
}
}
- // indicate that associated structure views will need an update
- viewport.setUpdateStructures(true);
- // propagate structure view update and sequence group to complement view
- viewport.addSequenceGroup(sg);
+ }
+ }
+ }
+
+ public void createSeqGroupFor(AlignmentPanel[] aps, Vector<BinaryNode> l,
+ Color col)
+ {
+
+ Vector<SequenceI> sequences = new Vector<>();
+
+ for (int j = 0; j < l.size(); j++)
+ {
+ SequenceI s1 = (SequenceI) l.elementAt(j).element();
+
+ if (!sequences.contains(s1))
+ {
+ sequences.addElement(s1);
}
}
- // notify the panel(s) to redo any group specific stuff
- // also updates structure views if necessary
+ ColourSchemeI cs = null;
+ SequenceGroup _sg = new SequenceGroup(sequences, null, cs, true, true,
+ false, 0, av.getAlignment().getWidth() - 1);
+
+ _sg.setName("JTreeGroup:" + _sg.hashCode());
+ _sg.setIdColour(col);
+
for (int a = 0; a < aps.length; a++)
{
- aps[a].updateAnnotation();
- final AlignViewportI codingComplement = aps[a].av
- .getCodingComplement();
- if (codingComplement != null)
+ SequenceGroup sg = new SequenceGroup(_sg);
+ AlignViewport viewport = aps[a].av;
+
+ // Propagate group colours in each view
+ if (viewport.getGlobalColourScheme() != null)
{
- ((AlignViewport) codingComplement).getAlignPanel()
- .updateAnnotation();
+ cs = viewport.getGlobalColourScheme().getInstance(viewport, sg);
+ sg.setColourScheme(cs);
+ sg.getGroupColourScheme().setThreshold(
+ viewport.getResidueShading().getThreshold(),
+ viewport.isIgnoreGapsConsensus());
+
+ if (viewport.getResidueShading().conservationApplied())
+ {
+ Conservation c = new Conservation("Group", sg.getSequences(null),
+ sg.getStartRes(), sg.getEndRes());
+ c.calculate();
+ c.verdict(false, viewport.getConsPercGaps());
+ sg.cs.setConservation(c);
+ }
}
+ // indicate that associated structure views will need an update
+ viewport.setUpdateStructures(true);
+ // propagate structure view update and sequence group to complement view
+ viewport.addSequenceGroup(sg);
}
}
import jalview.commands.CommandI;
import jalview.commands.OrderCommand;
import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.AlignmentView;
import jalview.datamodel.BinaryNode;
initTreePanel(alignPanel, null, null, newtree, inputData);
}
+ /**
+ * columnwise tree associated with positions in aa
+ *
+ * @param alignPanel
+ * @param fin
+ * @param title
+ * @param aa
+ */
+ public TreePanel(AlignmentPanel alignPanel, NewickFile fin,
+ AlignmentAnnotation aa, String title)
+ {
+ this(alignPanel, fin, title, null);
+ columnWise=true;
+ assocAnnotation = aa;
+
+
+ }
+ boolean columnWise=false;
+ AlignmentAnnotation assocAnnotation=null;
+ public boolean getColumnWise()
+ {
+ return columnWise;
+ }
+
public AlignmentI getAlignment()
{
return getTreeCanvas().getViewport().getAlignment();
&& !((SequenceNode) node).isDummy())
{
String newname = null;
- SequenceI sq = (SequenceI) ((SequenceNode) node).element();
+ SequenceI sq = (SequenceI) ((BinaryNode) node).element();
if (sq != null)
{
// search dbrefs, features and annotation
{
// String oldname = ((SequenceNode) node).getName();
// TODO : save oldname in the undo object for this modification.
- ((SequenceNode) node).setName(newname);
+ ((BinaryNode) node).setName(newname);
}
}
}
import java.util.Locale;
+import jalview.datamodel.BinaryNode;
import jalview.datamodel.SequenceNode;
import jalview.util.MessageManager;
*/
public class NewickFile extends FileParse
{
- SequenceNode root;
+ BinaryNode root;
private boolean HasBootstrap = false;
* @param newtree
* DOCUMENT ME!
*/
- public NewickFile(SequenceNode newtree)
+ public NewickFile(BinaryNode newtree)
{
root = newtree;
}
* @param distances
* DOCUMENT ME!
*/
- public NewickFile(SequenceNode newtree, boolean bootstrap,
+ public NewickFile(BinaryNode newtree, boolean bootstrap,
boolean distances)
{
root = newtree;
* @param rootdistance
* DOCUMENT ME!
*/
- public NewickFile(SequenceNode newtree, boolean bootstrap,
+ public NewickFile(BinaryNode newtree, boolean bootstrap,
boolean distances, boolean rootdistance)
{
root = newtree;
root = new SequenceNode();
- SequenceNode realroot = null;
- SequenceNode c = root;
+ BinaryNode realroot = null;
+ BinaryNode c = root;
int d = -1;
int cp = 0;
{
c.setRight(new SequenceNode(null, c, null, DefDistance,
DefBootstrap, false));
- c = (SequenceNode) c.right();
+ c = (BinaryNode) c.right();
}
else
{
if (c.left() != null)
{
// Dummy node for polytomy - keeps c.left free for new node
- SequenceNode tmpn = new SequenceNode(null, c, null, 0, 0, true);
+ BinaryNode tmpn = new SequenceNode(null, c, null, 0, 0, true);
tmpn.SetChildren(c.left(), c.right());
c.setRight(tmpn);
}
c.setLeft(new SequenceNode(null, c, null, DefDistance,
DefBootstrap, false));
- c = (SequenceNode) c.left();
+ c = (BinaryNode) c.left();
}
if (realroot == null)
else
{
// Find a place to put the leaf
- SequenceNode newnode = new SequenceNode(null, c, nodename,
+ BinaryNode newnode = new SequenceNode(null, c, nodename,
(HasDistances) ? distance : DefDistance,
(HasBootstrap) ? bootstrap : DefBootstrap, false);
parseNHXNodeProps(c, commentString2);
{
// Insert a dummy node for polytomy
// dummy nodes have distances
- SequenceNode newdummy = new SequenceNode(null, c, null,
+ BinaryNode newdummy = new SequenceNode(null, c, null,
(HasDistances ? 0 : DefDistance), 0, true);
newdummy.SetChildren(c.left(), newnode);
c.setLeft(newdummy);
// Just advance focus, if we need to
if ((c.left() != null) && (!c.left().isLeaf()))
{
- c = (SequenceNode) c.left();
+ c = (BinaryNode) c.left();
}
}
}
* @param commentString
* @param commentString2
*/
- private void parseNHXNodeProps(SequenceNode c, String commentString)
+ private void parseNHXNodeProps(BinaryNode c, String commentString)
{
// TODO: store raw comment on the sequenceNode so it can be recovered when
// tree is output
*
* @return DOCUMENT ME!
*/
- public SequenceNode getTree()
+ public BinaryNode getTree()
{
return root;
}
*
* @return DOCUMENT ME!
*/
- private String printNodeField(SequenceNode c)
+ private String printNodeField(BinaryNode c)
{
return ((c.getName() == null) ? "" : nodeName(c.getName()))
+ ((HasBootstrap) ? ((c.getBootstrap() > -1)
*
* @return DOCUMENT ME!
*/
- private String printRootField(SequenceNode root)
+ private String printRootField(BinaryNode root)
{
return (printRootInfo)
? (((root.getName() == null) ? "" : nodeName(root.getName()))
}
// Non recursive call deals with root node properties
- public void print(StringBuffer tf, SequenceNode root)
+ public void print(StringBuffer tf, BinaryNode root)
{
if (root != null)
{
{
if (root.isDummy())
{
- _print(tf, (SequenceNode) root.right());
- _print(tf, (SequenceNode) root.left());
+ _print(tf, root.right());
+ _print(tf, root.left());
}
else
{
tf.append("(");
- _print(tf, (SequenceNode) root.right());
+ _print(tf, root.right());
if (root.left() != null)
{
tf.append(",");
}
- _print(tf, (SequenceNode) root.left());
+ _print(tf, root.left());
tf.append(")" + printRootField(root));
}
}
}
// Recursive call for non-root nodes
- public void _print(StringBuffer tf, SequenceNode c)
+ public void _print(StringBuffer tf, BinaryNode c)
{
if (c != null)
{
{
if (c.isDummy())
{
- _print(tf, (SequenceNode) c.left());
+ _print(tf, c.left());
if (c.left() != null)
{
tf.append(",");
}
- _print(tf, (SequenceNode) c.right());
+ _print(tf, c.right());
}
else
{
tf.append("(");
- _print(tf, (SequenceNode) c.right());
+ _print(tf, c.right());
if (c.left() != null)
{
tf.append(",");
}
- _print(tf, (SequenceNode) c.left());
+ _print(tf, c.left());
tf.append(")" + printNodeField(c));
}
}
Console.warn("Not updating SequenceTreeMap for " + tree.getVorbaId());
return;
}
- Vector<SequenceNode> leaves = tp.getTree()
+ Vector<BinaryNode> leaves = tp.getTree()
.findLeaves(tp.getTree().getTopNode());
Treenode[] tn = tree.getTreenode(); // todo: select nodes for this
// particular tree
*/
public Treenode[] makeTreeNodes(TreeModel treeModel, Newick newick)
{
- Vector<SequenceNode> leaves = treeModel
+ Vector<BinaryNode> leaves = treeModel
.findLeaves(treeModel.getTopNode());
Vector tnv = new Vector();
Enumeration l = leaves.elements();
{
if (!((jalview.datamodel.SequenceNode) tnode).isPlaceholder())
{
- Object assocseq = ((jalview.datamodel.SequenceNode) tnode)
+ Object assocseq = ((BinaryNode) tnode)
.element();
if (assocseq instanceof SequenceI)
{
import jalview.datamodel.Annotation;
import jalview.datamodel.ColumnSelection;
import jalview.datamodel.ContactListI;
+import jalview.datamodel.ContactMatrixI;
import jalview.datamodel.HiddenColumns;
import jalview.datamodel.HiddenSequences;
import jalview.datamodel.ProfilesI;
return alignment.getContactListFor(_aa, column);
}
+ @Override
+ public ContactMatrixI getContactMatrix(
+ AlignmentAnnotation alignmentAnnotation)
+ {
+ return alignment.getContactMatrixFor(alignmentAnnotation);
+ }
+
+
/**
* get the consensus sequence as displayed under the PID consensus annotation
* row.
package jalview.ws.datamodel.alphafold;
+import java.util.ArrayList;
+import java.util.BitSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import jalview.analysis.AverageDistanceEngine;
+import jalview.bin.Console;
+import jalview.datamodel.BinaryNode;
import jalview.datamodel.ContactListI;
import jalview.datamodel.ContactListImpl;
import jalview.datamodel.ContactListProviderI;
{
return length;
}
+ List<BitSet> groups=null;
+ @Override
+ public boolean hasGroups()
+ {
+ return groups!=null;
+ }
+ String newick=null;
+ public String getNewickString()
+ {
+ return newick;
+ }
+ public void makeGroups(float thresh,boolean abs)
+ {
+ AverageDistanceEngine clusterer = new AverageDistanceEngine(null, null, this);
+ double height = clusterer.findHeight(clusterer.getTopNode());
+ newick = new jalview.io.NewickFile(clusterer.getTopNode(),false,true).print();
+
+ Console.trace("Newick string\n"+newick);
+
+ List<BinaryNode> nodegroups;
+ if (abs ? height > thresh : 0 < thresh && thresh < 1)
+ {
+ float cut = abs ? (float) (thresh / height) : thresh;
+ Console.debug("Threshold "+cut+" for height="+height);
+
+ nodegroups = clusterer.groupNodes(cut);
+ }
+ else
+ {
+ nodegroups = new ArrayList<BinaryNode>();
+ nodegroups.add(clusterer.getTopNode());
+ }
+
+ groups = new ArrayList<>();
+ for (BinaryNode root:nodegroups)
+ {
+ BitSet gpset=new BitSet();
+ for (BinaryNode leaf:clusterer.findLeaves(root))
+ {
+ gpset.set((Integer)leaf.element());
+ }
+ groups.add(gpset);
+ }
+ }
+
+ @Override
+ public BitSet getGroupsFor(int column)
+ {
+ for (BitSet gp:groups) {
+ if (gp.get(column))
+ {
+ return gp;
+ }
+ }
+ return ContactMatrixI.super.getGroupsFor(column);
+ }
}
}
ContactMatrixI matrix = new PAEContactMatrix(sequence,
(Map<String, Object>) paeDict);
+ ((PAEContactMatrix) matrix).makeGroups(5f, true);
AlignmentAnnotation cmannot = sequence.addContactList(matrix);
pdbAlignment.addAnnotation(cmannot);
ContactMatrixI matrix = new PAEContactMatrix(sm.getSequence(),
(Map<String, Object>) pae_obj);
-
+ ((PAEContactMatrix) matrix).makeGroups(5f, true);
AlignmentAnnotation cmannot = sm.getSequence().addContactList(matrix);
sm.getSequence().addAlignmentAnnotation(cmannot);
--- /dev/null
+package jalview.analysis;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import jalview.bin.Cache;
+import jalview.bin.Console;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.BinaryNode;
+import jalview.datamodel.ContactMatrixI;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+import jalview.gui.JvOptionPane;
+import jalview.io.DataSourceType;
+import jalview.io.FastaFile;
+import jalview.io.FileLoader;
+import jalview.io.FormatAdapter;
+import jalview.util.Platform;
+import jalview.ws.datamodel.alphafold.PAEContactMatrix;
+
+public class AverageDistanceEngineTest
+{
+
+ @BeforeClass(alwaysRun = true)
+ public void setUpJvOptionPane()
+ {
+ JvOptionPane.setInteractiveMode(false);
+ JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
+ }
+
+ @BeforeMethod(alwaysRun = true)
+ public void loadProperties()
+ {
+ Cache.loadProperties("test/jalview/bin/TestProps.jvprops");
+ }
+ @Test
+ public void testUPGMAEngine() throws Exception
+ {
+ AlignFrame af = new FileLoader(false).LoadFileWaitTillLoaded("examples/test_fab41.result/sample.a3m",DataSourceType.FILE);
+ AlignmentI seqs = af.getViewport().getAlignment();
+ SequenceI target = seqs.getSequenceAt(0);
+ File testPAE = new File("examples/test_fab41.result/test_fab41_predicted_aligned_error_v1.json");
+ List<Object> pae_obj = (List<Object>) Platform.parseJSON(new FileInputStream(testPAE));
+ if (pae_obj == null)
+ {
+ Assert.fail("JSON PAE file did not parse properly.");
+ }
+ ContactMatrixI matrix = new PAEContactMatrix(target,
+ (Map<String, Object>) pae_obj.get(0));
+ AlignmentAnnotation aa = target.addContactList(matrix);
+ System.out.println("Matrix has max="+matrix.getMax()+" and min="+matrix.getMin());
+ long start = System.currentTimeMillis();
+ AverageDistanceEngine clusterer = new AverageDistanceEngine(af.getViewport(), null, matrix);
+ System.out.println("built a tree in "+(System.currentTimeMillis()-start)*0.001+" seconds.");
+ StringBuffer sb = new StringBuffer();
+ System.out.println("Newick string\n"+ new jalview.io.NewickFile(clusterer.getTopNode(),true,true).print());
+
+ double height = clusterer.findHeight(clusterer.getTopNode());
+ // compute height fraction to cut
+ // PAE matrixes are absolute measure in angstrom, so
+ // cluster all regions within threshold (e.g. 2A) - if height above threshold. Otherwise all nodes are in one cluster
+ double thr=.2;
+ List<BinaryNode> groups;
+ if (height>thr)
+ {
+ float cut = (float) (thr/height);
+ System.out.println("Threshold "+cut+" for height="+height);
+ groups = clusterer.groupNodes(cut);
+ } else{
+ groups=new ArrayList<BinaryNode>();
+ groups.add(clusterer.getTopNode());
+ }
+ int n=1;
+ for (BinaryNode root:groups)
+ {
+ System.out.println("Cluster "+n++);
+ for (BinaryNode leaf:clusterer.findLeaves(root))
+ {
+ System.out.print(" "+leaf.getName());
+ }
+ System.out.println("\\");
+ }
+
+ }
+
+}
import jalview.analysis.SequenceIdMatcher;
import jalview.analysis.TreeModel;
+import jalview.datamodel.BinaryNode;
import jalview.datamodel.SequenceI;
import jalview.datamodel.SequenceNode;
import jalview.gui.JvOptionPane;
AssertJUnit.assertTrue(
stage + "Invalid Tree '" + nf.getWarningMessage() + "'",
nf.isValid());
- SequenceNode tree = nf.getTree();
+ BinaryNode tree = nf.getTree();
AssertJUnit.assertTrue(stage + "Null Tree", tree != null);
stage = "Creating newick file from testTree " + treename;
String gentree = new NewickFile(tree).print(nf.HasBootstrap(),
stage + "Newick file is invalid ('"
+ nf_regen.getWarningMessage() + "')",
nf_regen.isValid());
- SequenceNode tree_regen = nf.getTree();
+ BinaryNode tree_regen = nf.getTree();
AssertJUnit.assertTrue(stage + "Null Tree", tree_regen != null);
stage = "Compare original and generated tree" + treename;
- Vector<SequenceNode> oseqs, nseqs;
+ Vector<BinaryNode> oseqs, nseqs;
oseqs = new TreeModel(new SequenceI[0], null, nf)
.findLeaves(nf.getTree());
AssertJUnit.assertTrue(stage + "No nodes in original tree.",