Skip to content

widgets

pleat.shrink_rotate.widgets

Interactive widget for exploring shrink-rotate tessellations.

Requires the [notebook] extra (matplotlib + ipywidgets + ipympl). Use inside a Jupyter notebook with %matplotlib widget.

ShrinkRotateExplorer

ShrinkRotateExplorer(
    SRG,
    *,
    alpha0: float = 1 / 6,
    factor0: float = 0.58,
    figsize: tuple[float, float] = (7, 7),
    figure_id: str = "shrink-rotate"
)

Interactive shrink-rotate / reciprocal-figure explorer.

Build state once from an SRG (output of :func:pleat.shrink_rotate.shrink_rotate_pattern), then offer sliders for alpha and factor (or, in reparametrized mode, beta and gamma) plus a few display toggles.

Vertex positions on the supplied SRG are mutated in place at each tick, so downstream operations (e.g. fold_complete) see current geometry.

Parameters

SRG : Shrink-rotate graph with base_pos on every vertex and rotation_center on each twist face. alpha0, factor0: Initial slider values (alpha is in units of π). figsize : Matplotlib figure size. figure_id : Stable figure id; passed as num= to :func:plt.figure so re-displaying replaces the previous figure rather than stacking.

Notes

Call :meth:display to show the widget. Public attributes figure, alpha_slider, factor_slider etc. are exposed for further customisation.

Source code in pleat/shrink_rotate/widgets.py
def __init__(
    self,
    SRG,
    *,
    alpha0: float = 1 / 6,
    factor0: float = 0.58,
    figsize: tuple[float, float] = (7, 7),
    figure_id: str = "shrink-rotate",
) -> None:
    _require_notebook_deps()
    import ipywidgets as widgets
    import matplotlib.pyplot as plt
    from matplotlib.collections import LineCollection, PolyCollection

    self.SRG = SRG
    self._state = self._build_state(SRG)

    # Initial draw.
    self._reshrinkrotate(alpha0 * np.pi, factor0)

    # Suppress matplotlib's auto-display of the figure: we display the
    # canvas ourselves in :meth:`display`, so re-running the cell shows
    # the plot reliably (and exactly once).
    with plt.ioff():
        fig = plt.figure(num=figure_id, figsize=figsize, clear=True)
    fig.canvas.header_visible = False
    fig.canvas.footer_visible = False
    ax = fig.add_subplot(1, 1, 1)
    lc = LineCollection(self._segments(), antialiased=True, color="k", linewidth=1)
    pc = PolyCollection(self._polys(), antialiased=True, color="k", alpha=0.1)
    ax.add_collection(pc)
    ax.add_collection(lc)
    ax.autoscale()
    ax.set_axis_off()
    ax.set_aspect("equal", adjustable="datalim")

    self.figure = fig
    self.ax = ax
    self._lines = lc
    self._polys_artist = pc

    self.alpha_slider = widgets.FloatSlider(alpha0, min=-1, max=1, step=0.02, description="alpha/π")
    self.factor_slider = widgets.FloatSlider(factor0, min=0, max=6, step=0.05, description="factor")
    self.folded_cb = widgets.Checkbox(value=False, description="folded")
    self.reparam_cb = widgets.Checkbox(value=False, description="reparametrized")
    self.scale_folded_cb = widgets.Checkbox(value=False, description="scale_folded")
    self.show_lines_cb = widgets.Checkbox(value=False, description="show_lines")
    self.show_polys_cb = widgets.Checkbox(value=True, description="show_polys")
    self.info_label = widgets.Label(value="")

    self._last_reparametrized = False
    self._in_update = False  # re-entry guard

    self._ui = widgets.VBox(
        [
            widgets.HBox([self.alpha_slider, self.factor_slider]),
            widgets.HBox([self.folded_cb, self.reparam_cb, self.scale_folded_cb]),
            widgets.HBox([self.show_lines_cb, self.show_polys_cb]),
            self.info_label,
        ]
    )
    self._out = widgets.interactive_output(
        self._update,
        dict(
            alpha=self.alpha_slider,
            factor=self.factor_slider,
            folded=self.folded_cb,
            reparametrized=self.reparam_cb,
            scale_folded=self.scale_folded_cb,
            show_lines=self.show_lines_cb,
            show_polys=self.show_polys_cb,
        ),
    )

display

display()

Display the widget UI in a Jupyter notebook.

Re-displays the figure canvas explicitly, so re-executing a cell that calls :meth:display keeps showing the plot (with %matplotlib widget, the canvas widget from the previous execution is otherwise orphaned).

Source code in pleat/shrink_rotate/widgets.py
def display(self):
    """Display the widget UI in a Jupyter notebook.

    Re-displays the figure canvas explicitly, so re-executing a cell
    that calls :meth:`display` keeps showing the plot (with
    ``%matplotlib widget``, the canvas widget from the previous
    execution is otherwise orphaned).
    """
    from IPython.display import display as ipy_display

    ipy_display(self.figure.canvas, self._ui, self._out)