Search code examples
pythonmatplotlibtoolbar

Matplotlib Toolbar custom button show status


I have a matplotlib plot and am adding some more buttons. Fot one button, I would like to show the user that it is activated after clicking and deactivated after clicking again. In the Navigation Group of the toolbar the buttons are all depressed and darker when the are active. I would be perfect to have the same behavior but it would also be fine to only change the color of the button etc. I just need the user to know the status. Does anyone have an idea how this can be done? I already tried to inherite not from ToolBase but also from ToolHome and then change the description, but sadly it doesn't help. My minimal example is:

import matplotlib
import matplotlib.pyplot as plt
from matplotlib.backend_tools import ToolBase

matplotlib.rcParams["toolbar"] = "toolmanager"


class DrawPointsTool(ToolBase):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.points_enabled = False  # Initial state

    def trigger(self, sender, event, data=None):
        self.points_enabled = not self.points_enabled  # Toggle state
        if self.points_enabled:
            print("Drawing points enabled")
            # Here, you can implement your logic to handle point drawing
        else:
            print("Drawing points disabled")


if __name__ == "__main__":
    fig, ax = plt.subplots(2, 1)
    ax[0].set_title('Toggle Draw Points')

    # Add the custom button to the toolbar
    tm = fig.canvas.manager.toolmanager
    tm.add_tool('draw_points', DrawPointsTool)
    fig.canvas.manager.toolbar.add_tool(tm.get_tool('draw_points'), "toolgroup")
    plt.show()

Solution

  • It turns out, ToolToggleBase actually gives the solution. Copying ToolZoom and ZoomPanBase and carefully deleting the not used code, I figured out that super().trigger(sender, event, data) is necessary to make ToolToggleBase work. radio_group = 'default' adds it to theRadioButtons group of zoom and pan, so it gets unselected when another one is selected. So the functioning example code is:

    import matplotlib
    import matplotlib.pyplot as plt
    from matplotlib.backend_tools import ToolToggleBase
    
    matplotlib.rcParams["toolbar"] = "toolmanager"
    
    class DrawPointsTool(ToolToggleBase):
        radio_group = 'default'
        def __init__(self, *args):
            super().__init__(*args)
            self.points_enabled = False  # Initial state
    
        def trigger(self, sender, event, data=None):
            super().trigger(sender, event, data)
            self.points_enabled = not self.points_enabled  # Toggle state
            if self.points_enabled:
                print("Drawing points enabled")
                # Here, you can implement your logic to handle point drawing
            else:
                print("Drawing points disabled")
    
    
    
    if __name__ == "__main__":
        fig, ax = plt.subplots(2, 1)
        ax[0].set_title('Toggle Draw Points')
    
        # Add the custom button to the toolbar
        tm = fig.canvas.manager.toolmanager
        tm.add_tool('draw_points', DrawPointsTool)
        fig.canvas.manager.toolbar.add_tool(tm.get_tool('draw_points'), "toolgroup")
        plt.show()