class Projection: """ Data structure for keeping track of projections. ProjectionVisual is used to draw these as separate graphicsitems, but these can be as well presented by modifying existing edges and nodes. """ @staticmethod def get_base_label(node): head_part = as_text(node.label, omit_triangle=True, omit_index=True) if head_part: head_part = head_part.splitlines()[0].strip() last_char = head_part[-1] if len(head_part) > 1 and last_char in ('P', "'", "´"): head_part = head_part[:-1] return head_part def __init__(self, head, chains, rotator): super().__init__() self.color_key, self.color_tr_key = rotating_colors[rotator] self.style = g.NO_PROJECTIONS self.head = head # head in a projection is head node, not syntactic object self.chains = chains or [] self.visual = None self._changes = False self.base_label = '' def update_chains(self, chains): self.chains = chains def update_color(self): if self.base_label: code = sum([ord(c) for c in self.base_label]) else: code = 0 self.color_key, self.color_tr_key = rotating_colors[code % 8] def add_visual(self): self.visual = ProjectionVisual(self) def get_edges(self): """ Return edges between nodes in this chain as a list :return: """ res = set() for chain in self.chains: if len(chain) < 2: return [] child = chain[0] for parent in chain[1:]: edge = child.get_edge_to(parent, edge_type=g.ADJUNCT_EDGE if child.syntactic_node.adjunct else g.CONSTITUENT_EDGE) if edge: res.add(edge) child = parent return res def set_visuals(self, style): self.style = style for edge in self.get_edges(): if self not in edge.in_projections: edge.in_projections.append(self) edge.update() for chain in self.chains: if len(chain) > 1: for node in chain: if self not in node.in_projections: node.in_projections.append(self) if style == g.HIGHLIGHT_PROJECTIONS: if not self.visual: self.add_visual() ctrl.forest.add_to_scene(self.visual) elif self.visual.scene() != ctrl.graph_scene: ctrl.forest.add_to_scene(self.visual) else: self.visual.update() elif self.visual: ctrl.forest.remove_from_scene(self.visual) self.visual = None
def add_visual(self): self.visual = ProjectionVisual(self)
class Projection: """ Data structure for keeping track of projections. ProjectionVisual is used to draw these as separate graphicsitems, but these can be as well presented by modifying existing edges and nodes. """ def __init__(self, head, chains, rotator): super().__init__() self.color_id, self.color_tr_id = rotating_colors[rotator] self.colorized = False self.strong_lines = False self.highlighter = False self.head = head # head in a projection is head node, not syntactic object self.chains = chains or [] self.visual = None self._changes = False if head and chains: self.fix_labels() def update_chains(self, chains): changes = chains != self.chains self.chains = chains if changes: self._changes = True self.fix_labels() def add_visual(self): self.visual = ProjectionVisual(self) def get_edges(self): """ Return edges between nodes in this chain as a list :return: """ res = [] for chain in self.chains: if len(chain) < 2: return [] child = chain[0] for parent in chain[1:]: edge = child.get_edge_to(parent, edge_type=g.CONSTITUENT_EDGE) if edge: res.append(edge) child = parent return res def set_visuals(self, strong_lines, colorized, highlighter): self.colorized = colorized self.strong_lines = strong_lines if colorized: color_id = self.color_id else: color_id = None for edge in self.get_edges(): edge.in_projections.append(self) for chain in self.chains: if len(chain) > 1: for node in chain: node.in_projections.append(self) self.highlighter = highlighter if highlighter: if not self.visual: self.add_visual() ctrl.forest.add_to_scene(self.visual) elif self.visual.scene() != ctrl.graph_scene: ctrl.forest.add_to_scene(self.visual) else: self.visual.update() elif self.visual: ctrl.forest.remove_from_scene(self.visual) self.visual = None def fix_labels(self): """ If node has head, then start from this node, and move upwards labeling the nodes that also use the same head. If head is None, then remove label. :return: """ xbar = ctrl.settings.get("use_xbar_aliases") label = self.head.label if not xbar: for chain in self.chains: for node in chain[1:]: if node.label != label: node.label = label node.update_label() return head_base = strip_xbars(str(self.head.label or self.head.get_syn_label())) if head_base != str(self.head.label): self.head.label = head_base for chain in self.chains: new_label = head_base + "´" for node in chain[1:-1]: if str(node.label) != new_label: node.label = new_label node.update_label() node = chain[-1] new_label = head_base + "P" if str(node.display_label) != new_label: node.label = new_label node.update_label()