ttkbootstrap
ttkbootstrap copied to clipboard
Tk button style messes up Matplotlib toolbar
When using Matplotlib with the tk backend, the default styles for the tk widgets mess up the toolbar:
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 , 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?
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.
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.
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()
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.
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. ;-)
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 :/
@israel-dryer I finally got around to writing a proper patch that makes the matplotlib toolbar go from looking like this:
to this:
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.