daft-dev / daft

Render probabilistic graphical models using matplotlib
https://docs.daft-pgm.org
MIT License
675 stars 120 forks source link

nodes overflow the border and cannot be fully displayed #199

Closed Freakwill closed 3 weeks ago

Freakwill commented 2 months ago

When using daft for drawing, nodes overflow the border and cannot be fully displayed. Sometimes, one has to manually adjust the coordinates as shown in the following code. Is there a more natural way?


# Colors.
no_circle = {"ec": "#fff"}
pgm = daft.PGM(grid_unit=1.5, node_unit=1, dpi=150)

x_offset, y_offset = -0.55, 0.45  # adjust the coordinates of the nodes
pgm.add_node("z1", r"$z_1$", 1+x_offset, 1+y_offset)
pgm.add_node("z2", r"$z_2$", 2+x_offset, 1+y_offset)
pgm.add_node("z...", r"$\cdots$", 3+x_offset, 1+y_offset, plot_params=no_circle)
pgm.add_node("zT", r"$z_T$", 4+x_offset, 1+y_offset)
pgm.add_node("y1", r"$x_1$", 1+x_offset, 2.3+y_offset)
pgm.add_node("y2", r"$x_2$", 2+x_offset, 2.3+y_offset)
pgm.add_node("y...", r"$\cdots$", 3+x_offset, 2.3+y_offset, plot_params=no_circle)
pgm.add_node("yT", r"$x_T$", 4+x_offset, 2.3+y_offset)
pgm.add_node("x1", r"$x_1$", 1+x_offset, y_offset)
pgm.add_node("x2", r"$x_2$", 2+x_offset, y_offset)
pgm.add_node("x...", r"$\cdots$", 3+x_offset, y_offset, plot_params=no_circle)
pgm.add_node("xT", r"$x_T$", 4+x_offset, y_offset)

# Edges.
# pgm.add_edge("z1", "z2")
# pgm.add_edge("z2", "z...")
# pgm.add_edge("z...", "zT")
pgm.add_edge("x1", "z1")
pgm.add_edge("x2", "z2")
pgm.add_edge("xT", "zT")
pgm.add_edge("z1", "y2")
pgm.add_edge("z1", "yT")
pgm.add_edge("z2", "yT")

# Render and save.
pgm.render()
pgm.show()
pgm.figure.savefig("../src/nar.png")
dsfulf commented 3 weeks ago

What you are experiencing is a bug due to pgm.render() being called twice. pgm.show() is the following code:

    def show(self, *args, dpi=None, **kwargs):
        """
        Wrapper on :class:`PGM.render()` that calls `matplotlib.show()`
        immediately after.

        :param dpi: (optional)
            The DPI value to use for rendering.

        """

        self.render(dpi=dpi)
        plt.show(*args, **kwargs)

pgm.render() is provided as an exposed function to allow you to call directly into the matplotlib API if you would like to further manipulate the plot. By calling it twice, some unexpected behavior is causing your need to include offsets. Simply delete the separate call to pgm.render() and the issue is resolved.