def _set_data_node_output(self, node_id, node_attr, no_call, next_nds=None,
                              **kw):
        """
        Set the data node output from node estimations.

        :param node_id:
            Data node id.
        :type node_id: str

        :param node_attr:
            Dictionary of node attributes.
        :type node_attr: dict[str, T]

        :param no_call:
            If True data node estimations are not used.
        :type no_call: bool

        :return:
            If the output have been evaluated correctly.
        :rtype: bool
        """

        # Get data node estimations.
        est, wait_in = self._get_node_estimations(node_attr, node_id)

        if not no_call:
            if node_id is PLOT:
                est = est.copy()
                est[PLOT] = {'value': {'obj': self}}

            sf, args = False, ({k: v['value'] for k, v in est.items()},)
            if not (wait_in or 'function' in node_attr):
                # Data node that has just one estimation value.
                sf, args = True, tuple(args[0].values())
            try:
                # Final estimation of the node and node status.
                value = async_thread(self, args, node_attr, node_id, sf, **kw)
            except SkipNode:
                return False

            if value is not NONE:  # Set data output.
                self[node_id] = value

            value = {'value': value}  # Output value.
        else:
            self[node_id] = NONE  # Set data output.

            value = {}  # Output value.

        if next_nds:
            # namespace shortcuts for speed.
            wf_add_edge = self._wf_add_edge

            for u in next_nds:  # Set workflow.
                wf_add_edge(node_id, u, **value)

        else:
            # namespace shortcuts for speed.
            n, has, sub_sol = self.nodes, self.workflow.has_edge, self.sub_sol

            def no_visited_in_sub_dsp(i):
                node = n[i]
                if node['type'] == 'dispatcher' and has(i, node_id):
                    visited = sub_sol[self.index + node['index']]._visited
                    return node['inputs'][node_id] not in visited
                return True

            # List of functions.
            succ_fun = [u for u in self._succ[node_id]
                        if no_visited_in_sub_dsp(u)]

            # Check if it has functions as outputs and wildcard condition.
            if succ_fun and succ_fun[0] not in self._visited:
                # namespace shortcuts for speed.
                wf_add_edge = self._wf_add_edge

                for u in succ_fun:  # Set workflow.
                    wf_add_edge(node_id, u, **value)

        return True
Set the data node output from node estimations.

        :param node_id:
            Data node id.
        :type node_id: str

        :param node_attr:
            Dictionary of node attributes.
        :type node_attr: dict[str, T]

        :param no_call:
            If True data node estimations are not used.
        :type no_call: bool

        :return:
            If the output have been evaluated correctly.
        :rtype: bool