New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tree controller #492
Tree controller #492
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
empress/support_files/js/bp-tree.js
Outdated
var newToOld = {}; | ||
var oldToNew = {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this is a good opportunity to use the Map
object?
empress/support_files/js/empress.js
Outdated
this._treeData[i][this._tdToInd.arcendangle] = | ||
data.arcEndAngle[i]; | ||
data.arcEndAngle[j++]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you put the j
increment in a separate line? Seems a bit "hidden" this way.
tests/test-bp-tree.js
Outdated
@@ -929,7 +929,7 @@ require(["jquery", "ByteArray", "BPTree"], function ($, ByteArray, BPTree) { | |||
); | |||
|
|||
var keep = new Set(["4", "6", "7", "10", "11"]); | |||
var result = preShearBPTree.shear(keep); | |||
var result = preShearBPTree.shear(keep).tree; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add tests for the oldToNew and newToOld maps?
|
||
// initialize | ||
for (var i = 1; i <= this.currentTree.size; i++) { | ||
this.origToCur[i] = i; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest keeping the names consistent with the other classes.
This is just a suggestion but maybe consider these alternative names:
- "fullToSheared" and "shearedToFull"
- "pastToPresent" and "presentToPast"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same renaming would need to apply to the properties for example this.full = tree
and this.sheared = this.full.shear(tips)
....
* to Numbers representing the minimum, maximum, and | ||
* average non-root node length in the tree. | ||
*/ | ||
TreeController.prototype.getLengthStats = function () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for documenting this class so clearly. Although I am having a bit of a hard time figuring out when the methods refer to the current or to the original tree. What do you think about writing a property for "current" and "original" as part of the controller so that their methods are directly reused from those objects. Instead of having to replicate each method at this class' level.
For example using JavaScript's defineProperty. For example
Object.defineProperty(this, 'currentTree', {
value: this.model.currentTree,
writable: false
});
Other alternative I can think of is making the names of the methods more expressive. For example TreeController.prototype.getCurrentLengthStats
instead of just getLengthStats
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although I am having a bit of a hard time figuring out when the methods refer to the current or to the original tree.
In a way this is the point of TreeController
. From a users perspective, everything is in relation to the "original" tree which is why each method from BPTree
is replicated on the class level of TreeController
. Essentially, I wanted empress to be completely unaware of tree shearing so that additional logic does not need to be added to empress.js
to account for tree shearing.
The tldr is that empress is setup in such a way that it only interacts with tree through the various traversal methods (which handles the conversion between the sheared tree and original tree automatically). However, if you want more details, we can setup a quick meeting as it would be a lot easier to show you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes sense, thanks for explaining. I think the only methods that threw me off were those related to "names" which I think are a special case based on our offline discussion.
Thanks @ElDeveloper for posting a live demonstration! Like you said this PR is not meant to handle recoloring, the legend, etc. That will all be handled in a separate PR that deals with the UI. |
empress/support_files/js/empress.js
Outdated
// set up length getter | ||
var branchMethod = this.branchMethod; | ||
var checkLengthsChange = LayoutsUtil.shouldCheckBranchLengthsChanged( | ||
branchMethod | ||
); | ||
var lengthGetter = LayoutsUtil.getLengthMethod( | ||
branchMethod, | ||
this._tree | ||
this._tree.model.currentTree |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You may want to expose a method for the TreeController that exposes the tree of the model. Having large chains where you need to know the class of an attributes' attributes, the system can unintendedly get somewhat complex.
This looks awesome! Am I correct that it is not hooked up to the interface in any way yet? |
Yep, you are correct! Thanks for looking over.
…On (Mar-17-21|18:52), George Armstrong wrote:
This looks awesome! Am I correct that it is not hooked up to the interface in any way yet?
--
You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub:
https://urldefense.com/v3/__https://github.com/biocore/empress/pull/492*issuecomment-801555810__;Iw!!Mih3wA!UkuNGX4xbqrOvyQKpeO9dDvnOOIhbdBgf6lurjSopkj5sQwbbOzCIcfLZAwf8uQ$
|
merged @ElDeveloper's suggestions Co-authored-by: Yoshiki Vázquez Baeza <yoshiki@ucsd.edu>
The following artifacts were built for this PR: empire-biplot.qzv, empire.qzv, empress-tree.qzv, just-fm.qzv, plain.qzv |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks so much @kwcantrell!
Thanks so much @kwcantrell ! |
This PR implements a new object TreeController that will allow empress to support dynamic shearing based on feature metadata or even sample metadata. TreeController will shear the tree based on a set of tip names (based on https://github.com/wasade/improved-octo-waddle/blob/0e9e75b77238acda6752f59d940620f89607ba6b/bp/_bp.pyx#L732). Also, to make integration of TreeController as seamless as possible, all input and output of TreeController will be w.r.t the original tree. In other words empress.js will not know if a tree has been sheared. Instead, TreeController will internally convert its input from the original tree to the sheared tree and back. This makes handling the metadata A LOT easier since empress indexes metadata using a nodes post-order position (w.r.t the non-sheared tree).
In addition, TreeController introduces iterators for the post-order and in-order traversals (now we no longer need to do
for (i=1; i < this.tree.size; i++)
to perform post-order traversal. Instead, we simply dofor(node of this.tree.postorderTraversal())
)I've gone through a lot of different iterations of this PR so I am not sure how simple this final product turned out. So we can also setup a meeting if it makes reviewing this PR easier. 🙃