1# Copyright 2011-2017 by Peter Cock.  All rights reserved.
2#
3# This file is part of the Biopython distribution and governed by your
4# choice of the "Biopython License Agreement" or the "BSD 3-Clause License".
5# Please see the LICENSE file that should have been included as part of this
6# package.
7"""Genome Diagram Feature cross-link module."""
8
9from reportlab.lib import colors
10
11
12class CrossLink:
13    """Hold information for drawing a cross link between features."""
14
15    def __init__(
16        self, featureA, featureB, color=colors.lightgreen, border=None, flip=False
17    ):
18        """Create a new cross link.
19
20        Arguments featureA and featureB should GenomeDiagram feature objects,
21        or 3-tuples (track object, start, end), and currently must be on
22        different tracks.
23
24        The color and border arguments should be ReportLab colour objects, or
25        for border use a boolean False for no border, otherwise it defaults to
26        the same as the main colour.
27
28        The flip argument draws an inverted cross link, useful for showing a
29        mapping where one sequence has been reversed. It is conventional to
30        also use a different colour (e.g. red for simple links, blue for any
31        flipped links).
32        """
33        # Initialize attributes
34        self.featureA = featureA
35        self.featureB = featureB
36        self.color = color  # default color to draw the feature
37        self.border = border
38        self.flip = flip
39
40    @property
41    def startA(self):
42        """Start position of Feature A."""
43        try:
44            return self.featureA.start
45        except AttributeError:
46            track, start, end = self.featureA
47            return start
48
49    @property
50    def endA(self):
51        """End position of Feature A."""
52        try:
53            return self.featureA.end
54        except AttributeError:
55            track, start, end = self.featureA
56            return end
57
58    def _trackA(self, tracks):
59        try:
60            track, start, end = self.featureA
61            assert track in tracks
62            return track
63        except TypeError:
64            for track in tracks:
65                for feature_set in track.get_sets():
66                    if hasattr(feature_set, "features"):
67                        if self.featureA in feature_set.features.values():
68                            return track
69            return None
70
71    @property
72    def startB(self):
73        """Start position of Feature B."""
74        try:
75            return self.featureB.start
76        except AttributeError:
77            track, start, end = self.featureB
78            return start
79
80    @property
81    def endB(self):
82        """End position of Feature B."""
83        try:
84            return self.featureB.end
85        except AttributeError:
86            track, start, end = self.featureB
87            return end
88
89    def _trackB(self, tracks):
90        try:
91            track, start, end = self.featureB
92            assert track in tracks
93            return track
94        except TypeError:
95            for track in tracks:
96                for feature_set in track.get_sets():
97                    if hasattr(feature_set, "features"):
98                        if self.featureB in feature_set.features.values():
99                            return track
100            return None
101