我正在为 whatsapp 聊天编写数据分析程序,我的 tkinter 窗口中有一个 matplotlib 图。我知道如何自定义颜色,但如何将背景设置为透明?
f = Figure(figsize=(4.1, 4.1), dpi=100)
f.set_facecolor('xkcd:gray') # this should be transparent
a = f.add_subplot(111)
a.plot(dates, mes_count)
a.xaxis.set_major_locator(MaxNLocator(prune='both',nbins=6))
a.set_facecolor('xkcd:gray')
canvas = FigureCanvasTkAgg(f, mainloop.root)
canvas.get_tk_widget().place(x=190, y=80)
最佳答案
尝试将轴/图形的背景颜色与每个平台上的 tkinter 应用程序的背景颜色相匹配时,我感到有点沮丧,所以我做了一些挖掘:
一般来说,需要做两件事:
通过将 facecolor 设置为“none”,告诉 matplotlib 为图形和轴对象使用透明背景:
f.set_facecolor("none") a.set_facecolor("none")
告诉后端渲染器也使背景透明,例如将其保存为 png:
f.savefig('mygraph.png', transparent=True)
问题是:如何将此告诉 FigureCanvasTkAgg
? Looking at the sourcecode of FigureCanvasTk ,绘制时,可以看到 tk.Canvas
始终使用白色背景创建。 AFAIK Canvas 不能是透明的(请纠正我),但是当在没有特定背景颜色的情况下创建时,它将具有与其周围的框架相同的背景颜色,由 ttk.Style
给出它。所以我可以想到两种解决方法:
创建FigureCanvasTkAgg后,将 Canvas 的背景色设置为与当前样式相同:
s = ttk.Style() bg = s.lookup("TFrame", "background") bg_16bit = self.winfo_rgb(bg) bg_string = "#" + "".join([hex(bg_color >> 8)[2:] for bg_color in bg_16bit]) canvas.get_tk_widget().config(bg=bg_string)
第 3 和第 4 行是必需的,例如Windows,因为
s.lookup("TFrame", "background")
can return a system color name here , 然后需要将其转换为标准的#aabbcc
十六进制颜色制作您自己的
MyFigureCanvasTk
这只是 matplotlib 中代码的一个副本,跳过设置Canvas
的背景颜色:class MyFigureCanvasTk(FigureCanvasTk): # Redefine __init__ to get rid of the background="white" in the tk.Canvas def __init__(self, figure=None, master=None): super().__init__(figure) self._idle_draw_id = None self._event_loop_id = None w, h = self.get_width_height(physical=True) self._tkcanvas = tk.Canvas( master=master, #background="white" width=w, height=h, borderwidth=0, highlightthickness=0, ) self._tkphoto = tk.PhotoImage(master=self._tkcanvas, width=w, height=h) self._tkcanvas.create_image(w // 2, h // 2, image=self._tkphoto) self._tkcanvas.bind("<Configure>", self.resize) if sys.platform == "win32": self._tkcanvas.bind("<Map>", self._update_device_pixel_ratio) self._tkcanvas.bind("<Key>", self.key_press) self._tkcanvas.bind("<Motion>", self.motion_notify_event) self._tkcanvas.bind("<Enter>", self.enter_notify_event) self._tkcanvas.bind("<Leave>", self.leave_notify_event) self._tkcanvas.bind("<KeyRelease>", self.key_release) for name in ["<Button-1>", "<Button-2>", "<Button-3>"]: self._tkcanvas.bind(name, self.button_press_event) for name in ["<Double-Button-1>", "<Double-Button-2>", "<Double-Button-3>"]: self._tkcanvas.bind(name, self.button_dblclick_event) for name in ["<ButtonRelease-1>", "<ButtonRelease-2>", "<ButtonRelease-3>"]: self._tkcanvas.bind(name, self.button_release_event) # Mouse wheel on Linux generates button 4/5 events for name in "<Button-4>", "<Button-5>": self._tkcanvas.bind(name, self.scroll_event) # Mouse wheel for windows goes to the window with the focus. # Since the canvas won't usually have the focus, bind the # event to the window containing the canvas instead. # See https://wiki.tcl-lang.org/3893 (mousewheel) for details root = self._tkcanvas.winfo_toplevel() root.bind("<MouseWheel>", self.scroll_event_windows, "+") class MyFigureCanvasTkAgg(FigureCanvasAgg, MyFigureCanvasTk): def draw(self): super().draw() self.blit() def blit(self, bbox=None): _backend_tk.blit( self._tkphoto, self.renderer.buffer_rgba(), (0, 1, 2, 3), bbox=bbox )
这样我们就可以让图形与周围可能存在的任何背景颜色融为一体。它应该适用于所有平台(仅在 Windows 和 Linux 上测试,使用 python 3.11,tkinter 8.6.12)。也许这可以帮助遇到这个问题的人。
关于python-3.x - 使用 matplotlib 和 tkinter 的透明背景,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66489340/