def generate_graph(self, print_gradients: bool=False):
        """
        Generates a computation graph starting from the variable itself.

        :param print_gradients: A boolean indicating whether to print gradients in the graph.
        :return: A visualization of the computation graph.
        """
        try:
            from graphviz import Digraph
        except ImportError:
            raise ImportError("Please install graphviz to visualize the computation graphs. You can install it using `pip install graphviz`.")
        
        def wrap_text(text, width=40):
            """Wraps text at a given number of characters using HTML line breaks."""
            words = text.split()
            wrapped_text = ""
            line = ""
            for word in words:
                if len(line) + len(word) + 1 > width:
                    wrapped_text += line + "<br/>"
                    line = word
                else:
                    if line:
                        line += " "
                    line += word
            wrapped_text += line
            return wrapped_text
        
        def wrap_and_escape(text, width=40):
            return wrap_text(text.replace("<", "&lt;").replace(">", "&gt;"), width)
        
        topo = []
        visited = set()
        def build_topo(v):
            if v not in visited:
                visited.add(v)
                for predecessor in v.predecessors:
                    build_topo(predecessor)
                topo.append(v)

        def get_grad_fn_name(name):
            ws = name.split(" ")
            ws = [w for w in ws if "backward" in w]
            return " ".join(ws)
            
        build_topo(self)

        graph = Digraph(comment='Computation Graph starting from {}'.format(self.role_description))
        graph.attr(rankdir='TB')  # Set the graph direction from top to bottom
        graph.attr(ranksep='0.2')  # Adjust the spacing between ranks
        graph.attr(bgcolor='lightgrey')  # Set the background color of the graph
        graph.attr(fontsize='7.5')  # Set the font size of the graph
        
        for v in reversed(topo):
            # Add each node to the graph
            label_color = 'darkblue'
            
            node_label = (
                f"<b><font color='{label_color}'>Role: </font></b> {wrap_and_escape(v.role_description.capitalize())}"
                f"<br/><b><font color='{label_color}'>Value: </font></b> {wrap_and_escape(v.value)}"
            )
            

            if v.grad_fn is not None:
                node_label += f"<br/><b><font color='{label_color}'>Grad Fn: </font></b> {wrap_and_escape(get_grad_fn_name(str(v.grad_fn)))}"

            if v._reduce_meta != []:
                node_label += f"<br/><b><font color='{label_color}'>Reduce Meta: </font></b> {wrap_and_escape(str(v._reduce_meta))}"

            if print_gradients:
                node_label += f"<br/><b><font color='{label_color}'>Gradients: </font></b> {wrap_and_escape(v.get_gradient_text())}"
            # Update the graph node with modern font and better color scheme
            graph.node(
                str(id(v)), 
                label=f"<{node_label}>", 
                shape='rectangle', 
                style='filled', 
                fillcolor='lavender', 
                fontsize='8', 
                fontname="Arial", 
                margin='0.1', 
                pad='0.1', 
                width='1.2',
            )
            # Add forward edges from predecessors to the parent
            for predecessor in v.predecessors:
                graph.edge(str(id(predecessor)), str(id(v)))
        
        return graph

        Generates a computation graph starting from the variable itself.

        :param print_gradients: A boolean indicating whether to print gradients in the graph.
        :return: A visualization of the computation graph.
        
textgrad/variable.py