python-3.x - 使用 matplotlib 和 tkinter 的透明背景

标签 python-3.x matplotlib tkinter-canvas

我正在为 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 应用程序的背景颜色相匹配时,我感到有点沮丧,所以我做了一些挖掘:

一般来说,需要做两件事:

  1. 通过将 facecolor 设置为“none”,告诉 matplotlib 为图形和轴对象使用透明背景:

    f.set_facecolor("none")
    a.set_facecolor("none")
    
  2. 告诉后端渲染器也使背景透明,例如将其保存为 png:

    f.savefig('mygraph.png', transparent=True)
    

问题是:如何将此告诉 FigureCanvasTkAggLooking at the sourcecode of FigureCanvasTk ,绘制时,可以看到 tk.Canvas 始终使用白色背景创建。 AFAIK Canvas 不能是透明的(请纠正我),但是当在没有特定背景颜色的情况下创建时,它将具有与其周围的框架相同的背景颜色,由 ttk.Style 给出它。所以我可以想到两种解决方法:

  1. 创建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 十六进制颜色

  2. 制作您自己的 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/

相关文章:

mysql - 是否有 Django 等效项可以在 WHERE 子句中编写带有函数的 SQL SELECT 语句?

python-2.7 - Python-一个窗口中有多个3D图

python - tkinter 弹跳球

python - 将图像绘制到 tkinter Canvas

python - 通过最小化迭代次数来改进代码

python - 网络爬虫返回列表 vs 生成器 vs 生产者/消费者

python - matplotlib 中条形图的平均线

python - 调整 matplotlib 颜色条位置

python - 调用重置函数时,仅清除最后一行条目

Python all([6,7,8,9]) = True。但是 6 = 假