2025, Nov 20 13:00
How to Add a Custom CSV Export Button to the Matplotlib Toolbar with the TkAgg Tool Manager
Step-by-step guide to add a custom Save CSV action to the Matplotlib toolbar on TkAgg using the Tool Manager API and a ToolBase subclass. Clean export and UI.
Embedding a custom action in Matplotlib’s toolbar is a common need when you want a single, consistent UI surface for plot export. A typical first attempt uses a Matplotlib Button drawn inside the figure. It works, but the control sits on the canvas rather than living alongside the built-in toolbar items like the diskette “Save the figure”. If you are on the TkAgg backend, the way to place your control in the toolbar is to use the Tool Manager API.
Minimal example that adds a button on the canvas, not in the toolbar
import matplotlib.pyplot as plt
from matplotlib.widgets import Button
import csv
xs = [1, 2, 3, 4, 5]
ys = [2, 3, 5, 7, 11]
def write_csv(evt):
out_path = 'data.csv'
with open(out_path, 'w', newline='') as fh:
csvw = csv.writer(fh)
csvw.writerow(['X', 'Y'])
csvw.writerows(zip(xs, ys))
print(f'Data saved to {out_path}')
fig_obj, axis_obj = plt.subplots()
plt.plot(xs, ys, linestyle='None', marker='.', markersize=5)
plt.subplots_adjust(bottom=0.2)
btn_axes = plt.axes([0.81, 0.05, 0.1, 0.075])
btn_widget = Button(btn_axes, 'Save CSV')
btn_widget.on_clicked(write_csv)
plt.show()What’s actually going on
The code above attaches a button as a plotted UI element, not as a toolbar action. To get a button into the toolbar next to existing items, the approach needs to switch to the Tool Manager system. The relevant mechanism is a custom tool derived from ToolBase, which can be registered on the figure’s toolmanager and then placed in a toolbar group. With TkAgg, this can be enabled by setting the toolbar to toolmanager and registering the tool.
Solution: create a ToolBase subclass and register it with the toolbar
The flow is straightforward. Ensure TkAgg is selected, switch the toolbar implementation to toolmanager, implement a ToolBase subclass whose trigger calls your CSV export function, and add it to the toolbar. You can control placement by choosing the target group and index. Using the 'io' group with position 1 places it among I/O-related tools; using 'navigation' with position -1 places it in the navigation cluster. The following complete example wires everything together.
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import csv
from matplotlib.backend_tools import ToolBase
plt.rcParams['toolbar'] = 'toolmanager'
class CsvExportTool(ToolBase):
def trigger(self, *args, **kwargs):
write_csv(None)
def write_csv(evt):
out_path = 'data.csv'
with open(out_path, 'w', newline='') as fh:
csvw = csv.writer(fh)
csvw.writerow(['X', 'Y'])
csvw.writerows(zip(xs, ys))
print(f'Data saved to {out_path}')
xs = [1, 2, 3, 4, 5]
ys = [2, 3, 5, 7, 11]
fig_obj, axis_obj = plt.subplots()
plt.plot(xs, ys, linestyle='None', marker='.', markersize=5)
plt.subplots_adjust(bottom=0.2)
fig_obj.canvas.manager.toolmanager.add_tool('Save as CSV', CsvExportTool)
fig_obj.canvas.manager.toolbar.add_tool('Save as CSV', 'io', 1)
plt.show()If you prefer a different placement, you can register the tool in the 'navigation' group and use an index like -1 to position it relative to existing navigation controls. The grouping strings and positions influence where the button appears in the toolbar.
Why this matters
Keeping export actions in the toolbar aligns custom features with the user’s expectations and keeps the plotting area clean. It also ensures the action is accessible across backends that support the Tool Manager, with behavior that matches built-ins like “Save the figure”. For workflows centered on data export, that consistency helps reduce friction.
Takeaways
If your goal is a toolbar button with TkAgg, use the Tool Manager API rather than drawing a Button on the canvas. Derive a tool from ToolBase, set the toolbar to toolmanager, and register the tool in the desired group with an index for placement. For I/O-style actions, the 'io' group with a small positive index places your control alongside the save icon; for navigation-centric placement, the 'navigation' group with a negative index works as an alternative. If you embed Matplotlib in a tkinter app, another route exists via NavigationToolbar2TkAgg, which allows changing toolbar items, but the pattern above covers the pure Matplotlib setup with TkAgg.