ttkbootstrap icon indicating copy to clipboard operation
ttkbootstrap copied to clipboard

Tk button style messes up Matplotlib toolbar

Open daniilS opened this issue 3 years ago • 7 comments

When using Matplotlib with the tk backend, the default styles for the tk widgets mess up the toolbar: image It can be avoided without too much trouble by subclassing matplotlib.backends.backend_tkagg.NavigationToolbar2Tk and editing its _Button method, but it's still something to be aware of in case there's a better solution for it.

(Also, this wouldn't need to be an issue if Matplotlib caught up with the times and just used ttk...)

daniilS avatar Apr 13 '21 00:04 daniilS

@daniilS , I'm actually working on cleaning up the tkinter widgets now. Would you mind posting some sample code that I can use to test while I'm making those changes?

israel-dryer avatar Apr 13 '21 00:04 israel-dryer

Sure, here's a minimal example that creates an empty plot embedded in a tkinter window (it looks like it doesn't happen when letting Matplotlib create its own window: https://gist.github.com/daniilS/bd8a70b17b67ebc716345bc5c922131c

The culprit itself is here: https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/backends/_backend_tk.py#L561

Maybe this is really a Matplotlib issue, but I doubt this would be particularly high priority for them. I'm happy to provide an example for the documentation on how to subclass NavigationToolbar2Tk to avoid this, if you reckon that's enough of a solution.

daniilS avatar Apr 13 '21 00:04 daniilS

yeah, I don't think there's an easy ttkbootstrap way to make this look better because of how the buttons are configured inside matplotlib. You can use unicode characters to get a pretty nice looking substitute that would work with ANY theme, and without having to use any images. I'm sure this will render differently depending on the font set, etc... and there are other character options available to represent the same idea.

image

from tkinter import ttk
from ttkbootstrap import Style

chars = {
    'home': '\U0001F3E0',
    'left': '\U0001F878',
    'right': '\U0001F87a',
    'magnify': '\U0001f50d',
    'slider': '\U0001f39a',
    'move': '\u2931',
    'disk': '\U0001f5aa'
}

style = Style('yeti')
root = style.master
style.configure('char.primary.TButton', font='Helvetica 20')
frame = ttk.Frame(root, padding=20)
frame.pack(fill='both')

ttk.Button(frame, text=chars['home'], style='char.primary.TButton').pack(side='left', padx=1)
ttk.Button(frame, text=chars['left'], style='char.primary.TButton').pack(side='left', padx=1)
ttk.Button(frame, text=chars['right'], style='char.primary.TButton').pack(side='left', padx=1)
ttk.Separator(frame, orient='vertical').pack(side='left', fill='y', padx=5)
ttk.Button(frame, text=chars['move'], style='char.primary.TButton').pack(side='left', padx=1)
ttk.Button(frame, text=chars['magnify'], style='char.primary.TButton').pack(side='left', padx=1)
ttk.Button(frame, text=chars['slider'], style='char.primary.TButton').pack(side='left', padx=1)
ttk.Separator(frame, orient='vertical').pack(side='left', fill='y', padx=5)
ttk.Button(frame, text=chars['disk'], style='char.primary.TButton').pack(side='left', padx=1)

root.mainloop()

israel-dryer avatar Apr 13 '21 13:04 israel-dryer

Looks like Matplotlib did recently switch to using the png images in tkinter 8.6, so that solves the transparency issue. Annoyingly there's no good way to style the tk.checkbutton when it's using the indicatoron=False mode, which explains why the pan and zoom buttons don't get styled. I'll create a subclass of NavigationToolbar2Tk for my code which uses ttk widgets, and am happy to share it if you want to include it in the documentation in case anyone else runs into the same issue.

daniilS avatar Apr 13 '21 23:04 daniilS

Yeah for sure. If you send me a link to your code I can consider putting it into the gallery. I'm sure it would be helpful for others who use matplotlib and want make make it looks like it was designed in the last 10 years. ;-)

israel-dryer avatar Apr 14 '21 00:04 israel-dryer

Sure, I'll upload it and link you the project repository once it's reached a somewhat presentable state (what example could be more exciting than a data analysis tool!). It's a shame that tkinter has such a bad rep because people always associate it with the default tk look :/

daniilS avatar Apr 14 '21 00:04 daniilS

@israel-dryer I finally got around to writing a proper patch that makes the matplotlib toolbar go from looking like this: original to this: patched when embedding a plot in a tkinter window with ttkbootstrap. The file for the patch is here, and all you need to do is call its applyPatch method in a project at any point before displaying a matplotlib graph.

It might be worth adding a file like this to to the widgets module and including a note in the documentation in case anyone else ever runs into the same problem. The patch is only necessary for embedded plots as ttkbootstrap doesn't affect matplotlib's own popups, but it also has the somewhat nice side effect of causing the popups to use the native ttk theme instead of the old tk look.

daniilS avatar Sep 06 '21 11:09 daniilS