pythonmatplotlib

Matplotlib button "Save data as CSV" in the toolbar next to the "Save the figure as PNG" button


This works to add a "Save as CSV" button in a Matplotlib plot:

import matplotlib.pyplot as plt
from matplotlib.widgets import Button
import csv
X = [1, 2, 3, 4, 5]
Y = [2, 3, 5, 7, 11]
def save_as_csv(event):
    file_path = 'data.csv'
    with open(file_path, 'w', newline='') as file:
        writer = csv.writer(file)
        writer.writerow(['X', 'Y'])
        writer.writerows(zip(X, Y))
    print(f'Data saved to {file_path}')
fig, ax = plt.subplots()
plt.plot(X, Y, linestyle='None', marker='.', markersize=5)
plt.subplots_adjust(bottom=0.2)
ax_button = plt.axes([0.81, 0.05, 0.1, 0.075])
button = Button(ax_button, 'Save CSV')
button.on_clicked(save_as_csv)
plt.show()

How to have the button in the toolbar, next to the "Save the figure" (diskette icon), with TkAgg backend?


Solution

  • Based on documentation Tool Manager — Matplotlib:

    it needs to create custom class based on ToolBase

    from matplotlib.backend_tools import ToolBase
    plt.rcParams['toolbar'] = 'toolmanager'
    
    class SaveCSVTool(ToolBase):
    
        def trigger(self, *args, **kwargs):
            save_as_csv(None)  # <-- execute your original function
    

    and add it to toolmanager and toolbar with

    fig.canvas.manager.toolmanager.add_tool('Save as CSV', SaveCSVTool)
    fig.canvas.manager.toolbar.add_tool('Save as CSV', 'io', 1)
    

    Position for 'navigation', -1:

    enter image description here

    Position for 'io', 1:

    enter image description here

    Other groups in toolbar
    (I asked ChatGTP for groups because I couldn't find it in documetation but I didn't check if work)

    "navigation"  Tools for navigation (pan, zoom, home, back, forward).
    "toolgroup"   Used for mutually exclusive tools (e.g., toggle tools like pan/zoom).
    "default"     Default group for tools that don’t specify a group.
    "io"          Tools related to saving/exporting (e.g., save button).
    "zoompan"     Pan and zoom tools (can overlap with "navigation").
    "none"        Tools that should not be grouped or float independently.
    

    (finally I found some of them in source code)


    Full working code:

    import matplotlib
    matplotlib.use('TkAgg')  # to makes sure it uses `TkAgg` instead of `TkQt`
    
    import matplotlib.pyplot as plt
    #from matplotlib.widgets import Button
    import csv
    
    from matplotlib.backend_tools import ToolBase #, ToolToggleBase
    plt.rcParams['toolbar'] = 'toolmanager'
    
    # --- classes ---
    
    class SaveCSVTool(ToolBase):
        #default_keymap = 'c'  # keyboard shortcut
        #description = 'Save As CSV'
        #image = r'C:\path\to\image.png'
        #image = 'mpl-data/images/filesave'  # this is path from button `Save the figure` but it doesn't works for me in custon button
        #image = 'filesave.png`   # this works for me but show warning that it is deprecated
    
        def trigger(self, *args, **kwargs):
            save_as_csv(None)
    
    # --- functions ---
    
    def save_as_csv(event):
        file_path = 'data.csv'
        with open(file_path, 'w', newline='') as file:
            writer = csv.writer(file)
            writer.writerow(['X', 'Y'])
            writer.writerows(zip(X, Y))
        print(f'Data saved to {file_path}')
    
    # --- main ---
    
    X = [1, 2, 3, 4, 5]
    Y = [2, 3, 5, 7, 11]
    
    fig, ax = plt.subplots()
    plt.plot(X, Y, linestyle='None', marker='.', markersize=5)
    plt.subplots_adjust(bottom=0.2)
    
    #ax_button = plt.axes([0.81, 0.05, 0.1, 0.075])
    #button = Button(ax_button, 'Save CSV')
    #button.on_clicked(save_as_csv)
    
    fig.canvas.manager.toolmanager.add_tool('Save as CSV', SaveCSVTool)
    fig.canvas.manager.toolbar.add_tool('Save as CSV', 'io', 1)
    
    plt.show()