示例#1
0
 def __init__(self,
              importance_score_map,
              show_input_ports,
              show_output_ports,
              vertical_orientation=True):
     """Args:
         importance_score_map (ImportanceScoreMap):
         show_input_ports (bool):
         show_output_ports (bool):
         vertical_orientation (bool): True if the graph should be drawn
             from top to bottom, False if it should be drawn from left to
             right.
     """
     self.__b = DotBuilder(vertical_orientation)
     self.__e_reg = _EdgesRegister()
     self.__n_reg = _NodesRegister()
     self.__importance_score_map = importance_score_map
     self.__show_input_ports = show_input_ports
     self.__show_output_ports = show_output_ports
示例#2
0
 def __init__(self, importance_score_map,
              show_input_ports, show_output_ports,
              vertical_orientation=True):
     """Args:
         importance_score_map (ImportanceScoreMap):
         show_input_ports (bool):
         show_output_ports (bool):
         vertical_orientation (bool): True if the graph should be drawn
             from top to bottom, False if it should be drawn from left to
             right.
     """
     self.__b = DotBuilder(vertical_orientation)
     self.__e_reg = _EdgesRegister()
     self.__n_reg = _NodesRegister()
     self.__importance_score_map = importance_score_map
     self.__show_input_ports = show_input_ports
     self.__show_output_ports = show_output_ports
示例#3
0
class DotBuilderWrapper:
    """Wrapper for DotBuilder class.

    It is an intermediate layer between the dot format and business logic.
    It translates business-level node objects to concepts of the dot format.
    """
    def __init__(self,
                 importance_score_map,
                 show_input_ports,
                 show_output_ports,
                 vertical_orientation=True):
        """Args:
            importance_score_map (ImportanceScoreMap):
            show_input_ports (bool):
            show_output_ports (bool):
            vertical_orientation (bool): True if the graph should be drawn
                from top to bottom, False if it should be drawn from left to
                right.
        """
        self.__b = DotBuilder(vertical_orientation)
        self.__e_reg = _EdgesRegister()
        self.__n_reg = _NodesRegister()
        self.__importance_score_map = importance_score_map
        self.__show_input_ports = show_input_ports
        self.__show_output_ports = show_output_ports

    def __map(self, name):
        return _NamesConverter.run(name)

    def add_node(self, name, node):
        """Args:
            name (string): name of the node
            node (vipe.pipeline.pipeline.Node): data about the node
        """
        if self.__n_reg.contains(name):
            raise Exception('More than two nodes with the same name '
                            '(here: "{}") are not allowed'.format(name))
        color = self.__get_color(node.importance)
        if name in [
                Pipeline.get_input_node_name(),
                Pipeline.get_output_node_name()
        ]:
            self.__n_reg.add(name, _NodeInfo(True, True))
            self.__add_advanced_node(name, node, True, True, color, 'folder')
            return

        importance_score = \
            self.__importance_score_map.get_score(node.importance)
        if importance_score > -1:
            self.__n_reg.add(
                name,
                _NodeInfo(self.__show_input_ports, self.__show_output_ports))
            self.__add_advanced_node(name, node, self.__show_input_ports,
                                     self.__show_output_ports, color)
        else:
            self.__n_reg.add(name, _NodeInfo(False, False))
            if importance_score == -1:
                self.__b.add_node(self.__map(name),
                                  labels=[''],
                                  shape='box',
                                  width=0.2,
                                  height=0.2,
                                  color=color)
            elif importance_score < -1:
                self.__b.add_node(self.__map(name),
                                  labels=[''],
                                  shape='box',
                                  width=0.1,
                                  height=0.1,
                                  color=color)

    @staticmethod
    def __get_color(importance):
        color = 'white'
        if importance == NodeImportance.normal:
            color = 'cyan'
        elif importance == NodeImportance.low:
            color = 'lightcyan'
        return color

    def __add_advanced_node(self,
                            node_name,
                            node,
                            show_input_ports,
                            show_output_ports,
                            color,
                            shape=None):
        """
        Args:
            shape(string): shape of the node. If None, the default
                approach of deciding which shape is appropriate is used.
        """
        labels = [node_name, 'type={}'.format(node.type)]
        if show_input_ports or show_output_ports:
            input_ports = []
            if show_input_ports:
                input_ports = self.__port_labels_to_PortNames(
                    node.input_ports.keys(), True)
            output_ports = []
            if show_output_ports:
                output_ports = self.__port_labels_to_PortNames(
                    node.output_ports.keys(), False)
            labels = [
                PortsLabelPrinter().run(labels, input_ports, output_ports,
                                        color)
            ]
            if shape is None:
                shape = 'none'
            self.__b.add_node(self.__map(node_name),
                              labels=labels,
                              shape=shape,
                              use_raw_labels=True)
        else:
            if shape is None:
                shape = 'box'
            self.__b.add_node(self.__map(node_name),
                              labels=labels,
                              shape=shape,
                              color=color)

    @staticmethod
    def __port_labels_to_PortNames(port_labels, are_input_ports):
        names = []
        for n in sorted(port_labels):
            internal_name = DotBuilderWrapper.__port_name_to_internal_name(
                n, are_input_ports)
            names.append(PortName(n, internal_name))
        return names

    @staticmethod
    def __port_name_to_internal_name(name, is_input_port):
        if name is None:
            return None
        prefix = 'output_'
        if is_input_port:
            prefix = 'input_'
        return '{}{}'.format(prefix, name)

    def add_data_node(self, data_id):
        """Args:
            data_id (string): data ID
        """
        self.__b.add_node(self.__map(data_id), shape='point')

    def add_edge(self, start, end):
        """Add connection between two nodes.

        The name field of the DataAddress might be a name of a node or a
        data ID - in the latter case the address corresponds to data.
        The port field of the address might be set to `None`. It is
        always `None` if the address corresponds to data.

        Args:
            start (DataAddress): start of the connection
            end (DataAddress): end of the connection
        """
        start_output_port = None
        if self.__n_reg.contains(start.node) and \
                self.__n_reg.get(start.node).has_visible_output_ports:
            start_output_port = start.port
        end_input_port = None
        if self.__n_reg.contains(end.node) and \
                self.__n_reg.get(end.node).has_visible_input_ports:
            end_input_port = end.port
        if start_output_port is not None or end_input_port is not None:
            self.__b.add_edge(
                self.__map(start.node),
                self.__port_name_to_internal_name(start_output_port, False),
                self.__map(end.node),
                self.__port_name_to_internal_name(end_input_port, True))
        else:
            assert start_output_port is None
            assert end_input_port is None
            if not self.__e_reg.contains(start.node, end.node):
                self.__b.add_edge(self.__map(start.node), None,
                                  self.__map(end.node), None)
        if not self.__e_reg.contains(start.node, end.node):
            self.__e_reg.add(start.node, end.node)

    def get_result(self):
        """Return:
            string: resulting graph in dot format
        """
        return self.__b.get_result()
示例#4
0
class DotBuilderWrapper:
    """Wrapper for DotBuilder class.

    It is an intermediate layer between the dot format and business logic.
    It translates business-level node objects to concepts of the dot format.
    """

    def __init__(self, importance_score_map,
                 show_input_ports, show_output_ports,
                 vertical_orientation=True):
        """Args:
            importance_score_map (ImportanceScoreMap):
            show_input_ports (bool):
            show_output_ports (bool):
            vertical_orientation (bool): True if the graph should be drawn
                from top to bottom, False if it should be drawn from left to
                right.
        """
        self.__b = DotBuilder(vertical_orientation)
        self.__e_reg = _EdgesRegister()
        self.__n_reg = _NodesRegister()
        self.__importance_score_map = importance_score_map
        self.__show_input_ports = show_input_ports
        self.__show_output_ports = show_output_ports

    def __map(self, name):
        return _NamesConverter.run(name)

    def add_node(self, name, node):
        """Args:
            name (string): name of the node
            node (vipe.pipeline.pipeline.Node): data about the node
        """
        if self.__n_reg.contains(name):
            raise Exception('More than two nodes with the same name '
                            '(here: "{}") are not allowed'.format(name))
        color = self.__get_color(node.importance)
        if name in [Pipeline.get_input_node_name(),
                    Pipeline.get_output_node_name()]:
            self.__n_reg.add(name, _NodeInfo(True, True))
            self.__add_advanced_node(name, node, True, True, color, 'folder')
            return

        importance_score = \
            self.__importance_score_map.get_score(node.importance)
        if importance_score > -1:
            self.__n_reg.add(name, _NodeInfo(self.__show_input_ports,
                                             self.__show_output_ports))
            self.__add_advanced_node(name, node,
                                     self.__show_input_ports,
                                     self.__show_output_ports, color)
        else:
            self.__n_reg.add(name, _NodeInfo(False, False))
            if importance_score == -1:
                self.__b.add_node(self.__map(name), labels=[''], shape='box',
                                  width=0.2, height=0.2, color=color)
            elif importance_score < -1:
                self.__b.add_node(self.__map(name), labels=[''], shape='box',
                                  width=0.1, height=0.1, color=color)

    @staticmethod
    def __get_color(importance):
        color = 'white'
        if importance == NodeImportance.normal:
            color = 'cyan'
        elif importance == NodeImportance.low:
            color = 'lightcyan'
        return color

    def __add_advanced_node(self, node_name, node,
                            show_input_ports, show_output_ports, color,
                            shape=None):
        """
        Args:
            shape(string): shape of the node. If None, the default
                approach of deciding which shape is appropriate is used.
        """
        labels = [node_name, 'type={}'.format(node.type)]
        if show_input_ports or show_output_ports:
            input_ports = []
            if show_input_ports:
                input_ports = self.__port_labels_to_PortNames(
                    node.input_ports.keys(), True)
            output_ports = []
            if show_output_ports:
                output_ports = self.__port_labels_to_PortNames(
                    node.output_ports.keys(), False)
            labels = [PortsLabelPrinter().run(
                labels, input_ports, output_ports, color)]
            if shape is None:
                shape = 'none'
            self.__b.add_node(self.__map(node_name), labels=labels,
                              shape=shape, use_raw_labels=True)
        else:
            if shape is None:
                shape = 'box'
            self.__b.add_node(self.__map(node_name), labels=labels,
                              shape=shape, color=color)

    @staticmethod
    def __port_labels_to_PortNames(port_labels, are_input_ports):
        names = []
        for n in sorted(port_labels):
            internal_name = DotBuilderWrapper.__port_name_to_internal_name(
                n, are_input_ports)
            names.append(PortName(n, internal_name))
        return names

    @staticmethod
    def __port_name_to_internal_name(name, is_input_port):
        if name is None:
            return None
        prefix = 'output_'
        if is_input_port:
            prefix = 'input_'
        return '{}{}'.format(prefix, name)

    def add_data_node(self, data_id):
        """Args:
            data_id (string): data ID
        """
        self.__b.add_node(self.__map(data_id), shape='point')

    def add_edge(self, start, end):
        """Add connection between two nodes.

        The name field of the DataAddress might be a name of a node or a
        data ID - in the latter case the address corresponds to data.
        The port field of the address might be set to `None`. It is
        always `None` if the address corresponds to data.

        Args:
            start (DataAddress): start of the connection
            end (DataAddress): end of the connection
        """
        start_output_port = None
        if self.__n_reg.contains(start.node) and \
                self.__n_reg.get(start.node).has_visible_output_ports:
            start_output_port = start.port
        end_input_port = None
        if self.__n_reg.contains(end.node) and \
                self.__n_reg.get(end.node).has_visible_input_ports:
            end_input_port = end.port
        if start_output_port is not None or end_input_port is not None:
            self.__b.add_edge(
                self.__map(start.node),
                self.__port_name_to_internal_name(start_output_port, False),
                self.__map(end.node),
                self.__port_name_to_internal_name(end_input_port, True))
        else:
            assert start_output_port is None
            assert end_input_port is None
            if not self.__e_reg.contains(start.node, end.node):
                self.__b.add_edge(self.__map(start.node), None,
                                  self.__map(end.node), None)
        if not self.__e_reg.contains(start.node, end.node):
            self.__e_reg.add(start.node, end.node)

    def get_result(self):
        """Return:
            string: resulting graph in dot format
        """
        return self.__b.get_result()