Open StuntsPT opened 3 years ago
I have further figured out that mark.markers
(from tre.draw()
) is returning an empty list (is this intended?).
Also, marker
from canvas.legend([("text", marker)])
expects a string that looks like XML
>>> m2.markers[0]
<marker shape='s' mstyle='fill:rgb(0%,50.2%,0%);fill-opacity:1.0;opacity:1;stroke:rgb(0%,50.2%,0%);stroke-opac
ity:1.0'/>
But I can't find anything on mark
from tre.draw()
that looks like this. What am I missing?
Ok, so I was unable to obtain a marker
object from toytree, but I managed to work around the issue by using toyplot's marker.create()
to create a marker
object using the variables I had originally used to define the node markers in toytree like this:
markers = [toyplot.marker.create(shape="o", size=18, mstyle={"fill": x}) for x in my_palette]
legend_markers = list(zip(bootstraps, markers))
canvas.legend(legend_markers,
corner=("top-right", 20, 170, 140))
Where my_palette
and bootstraps
contain the colours and intervals used on toytree nodes.
If you find this important enough, I can easily add it to toytree's documentation (just let me know where I should place it).
Hey @StuntsPT,
Great solution!
The legend creation in toyplot is not super intuitive. Saving the marker objects and passing them to the legend function is easiest, but not always doable when you have complex plots. Your approach of making custom marker objects is a great solution.
I was very back-and-forth when designing toytree in deciding whether to return portions of tree drawings as a collection of separate toyplot marker objects (e.g., a graph for the tree, text for the tips, scatterplot for nodes, etc.) versus creating a custom ToyTreeMark class object. In v1 I followed the first approach, whereas v2 does the latter. The custom marker object approach had some significant advantages for the size and speed of creation of the objects, and for setting margin spacing around them.
That being said, I think you are right that the mark.markers list is a clear place for storing the underlying toyplot markers that compose the nodes or edges, but its something that I never filled (it's just an inherited feature of the Mark class).
I definitely welcome any contributions to the docs or source, I'm really interested in getting more developers involved with toytree. Shoot me an email if you're interested and I can fill you in on some of the future plans.
I'll leave this issue open for now since I think filling the mark.markers
list in render.py would be the best solution.
Thanks!
The legend creation in toyplot is not super intuitive. Saving the marker objects and passing them to the legend function is easiest, but not always doable when you have complex plots. Your approach of making custom marker objects is a great solution.
It took me a while to get my head around it, but I managed a work around, that doesn't make me want to puke afterwards. =-)
I was very back-and-forth when designing toytree in deciding whether to return portions of tree drawings as a collection of separate toyplot marker objects (e.g., a graph for the tree, text for the tips, scatterplot for nodes, etc.) versus creating a custom ToyTreeMark class object. In v1 I followed the first approach, whereas v2 does the latter. The custom marker object approach had some significant advantages for the size and speed of creation of the objects, and for setting margin spacing around them.
Your v2 also seems like the best approach for extending the original markers if required in the future.
I definitely welcome any contributions to the docs or source, I'm really interested in getting more developers involved with toytree. Shoot me an email if you're interested and I can fill you in on some of the future plans.
Cool, expect an email as soon as I get some breathing space. =-)
That being said, I think you are right that the mark.markers list is a clear place for storing the underlying toyplot markers that compose the nodes or edges, but its something that I never filled (it's just an inherited feature of the Mark class). I'll leave this issue open for now since I think filling the mark.markers list in render.py would be the best solution.
In that case, maybe altering the issue title is reasonable in order to make it clear what is being addressed here?
This is a help request, but I cannot seem to find in the docs how to do this. I want to add a legend to my tree, to explain what each mode colour means (they have different colours based on support value). I have looked at toytree's docs, and realized I had to add it via toyplot directly. So far so good. I dove into pyplot's docs, and found this: https://toyplot.readthedocs.io/en/stable/labels-and-legends.html#canvas-legends and this: https://toyplot.readthedocs.io/en/stable/toyplot.canvas.html#toyplot.canvas.Canvas.legend
This led me to the
canvas
object that is returned byIn order to draw a legend I can use toyplot's API and call
canvas.legend()
. This requires (at least) a list ofentries
each being a tuple containing a custom string and amarker
/mark
object. If I prove it themark
object returned bytre.draw()
, I can see the text string being draw in the canvas, but what I can't seem to figure out is how can I call each of the node styles present in my tree in order to label each of them with a custom string.Can you please assist me in obtaining this information?
Thank you very much in advance!