Skip to content
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

How to align the highlight bins and the images automatically #32

Closed
klcym opened this issue May 15, 2024 · 4 comments
Closed

How to align the highlight bins and the images automatically #32

klcym opened this issue May 15, 2024 · 4 comments

Comments

@klcym
Copy link

klcym commented May 15, 2024

Dear Giorgio :

I want to align the highlight bins and the images and I dont want to change the tree into the cladogram style. What can I do?

image

Thanks for your help.

@arklumpus
Copy link
Owner

Hi! For the images, within the options for the Draw image module, you need to set the Anchor to Origin, and then use the same X value for the position of all images.

For the highlights, I'm afraid there is no easy way to do this at the moment; you would have to manually adjust the Right margin of each highlight. I'll figure something out for the next update!

Another alternative would be to use a custom script to draw the highlights - I can give you some example code to get started, if you're interested.

@klcym
Copy link
Author

klcym commented May 16, 2024

Thanks for your reply. I will try to use the custom script.😊

@arklumpus
Copy link
Owner

OK, here is an example that produces the following tree:

customHighlights

And here is the tree file: customHighlights.zip

Essentially, the highlight colour is stored as an attribute on the LCA of each highlighted group; the script searches for nodes with this attribute and draws a rectangle around them.

Here is the source code (you can also access it from the tree file, by opening the options of the Custom script module.

Source code
using PhyloTree;
using System.Collections.Generic;
using VectSharp;
using TreeViewer;
using System.Linq;

namespace a6d3baabb494a4099b6ff50915d4ed748
{
    //Do not change class name
    public static class CustomCode
    {
        //Do not change method signature
        public static Point[] PerformPlotAction(TreeNode tree, Dictionary<string, Point> coordinates, Graphics graphics, InstanceStateData stateData)
        {
            // Name of the attribute where the highlight colour is stored.
            string attribute = "HighlightColour";

            // Margins for the highlight.
            double marginTop = 6;
            double marginLeft = 10;
            double marginBottom = 6;
            double marginRight = 25;

            // Get the X coordinate that is farthest from the root.
            double rightmostX = coordinates.Values.Select(point => point.X).Max();

            // Traverse the tree
            foreach (TreeNode node in tree.GetChildrenRecursiveLazy())
            {
                // Check if the node has the attribute
                if (node.Attributes.TryGetValue(attribute, out object attributeVal) && attributeVal is string attributeString)
                {
                    // Parse the colour.
                    Colour highlightCol = Colour.FromCSSString(attributeString).Value;

                    // The left side of the highlight corresponds to the coordinates of the node (minus the margin).
                    double leftX = coordinates[node.Id].X - marginLeft;

                    // The right side of the highlight is fixed.
                    double rightX = rightmostX + marginRight;

                    // The top of the highlight will be at the minimum Y coordinate of the node's children.
                    double topY = node.GetChildrenRecursiveLazy().Select(childNode => coordinates[childNode.Id].Y).Min() - marginTop;

                    // The bottom of the highlight will be at the maximum Y coordinate of the node's children.
                    double bottomY = node.GetChildrenRecursiveLazy().Select(childNode => coordinates[childNode.Id].Y).Max() + marginBottom;

                    // Create the linear gradient brush.
                    LinearGradientBrush brush = new LinearGradientBrush(
                            new Point(leftX, (topY + bottomY) * 0.5), // Start point
                            new Point(rightX, (topY + bottomY) * 0.5), // End point
                            new VectSharp.GradientStop(highlightCol.WithAlpha(0), 0), new VectSharp.GradientStop(highlightCol, 1)); // Gradient colour stops.

                    // Fill the highlight rectangle (tagging the rectangle with the node Id makes it selectable).
                    graphics.FillRectangle(leftX, topY, rightX - leftX, bottomY - topY, brush, tag: node.Id);
                }
            }
            
            // In theory, we should return the coordinates of the top-left and bottom-right corners of the area containing
            // everything that has been drawn by this script. However, since we are not extending the plot area, in this
            // case it doesn't matter.
            Point topLeft = new Point();
            Point bottomRight = new Point();
            return new Point[] { topLeft, bottomRight };
        }
    }
}

Let me know if you have any questions!

@klcym
Copy link
Author

klcym commented May 17, 2024

Wow, that's great!

@klcym klcym closed this as completed May 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants