使用 GTK 后端更改 matplotlib 导航工具栏中的图标

Changing the icon in matplotlib navigation toolbar using GTK backend

之前在 Stack Overflow 上问过类似的问题,但是,其中 none 涉及 GTK 后端,并且 none 涉及需要更改后端正在搜索的路径。这里的类似问题包括 this and this among others. The relevant code for the GTK backend is here.

顺便说一句,如果它是相关的,我正在使用 PyInstaller 冻结这个 Python 脚本,我想“更改”图标的原因是因为在某些 Windows 计算机上我我发现尽管图像出现在正确的位置,但图标是导航工具栏的断开链接:

\dist\<script name>\matplotlib\mpl-data\images\<image_file>-symbolic.svg

以及具有 GTK 后端所需格式的图像 (f'{image_file}-symbolic.svg')。我不确定为什么会出现这个问题并且花了很多时间无处可去,所以我认为可能的解决方法是将图像作为我的仓库的一部分存储在我选择的位置并强制它们被使用脚本(如果它是一些奇怪的环境变量或路径问题)。使用下面的示例,我可以成功更改工具提示和 image/icon,但我无法更改图像的位置。 toolitems的第三个参数控制图像:

list of toolitems to add to the toolbar, format is:
(
   text, # the text of the button (often not visible to users)
   tooltip_text, # the tooltip shown on hover (where possible)
   image_file, # name of the image for the button (without the extension)
   name_of_method, # name of the method in NavigationToolbar2 to call
)

显然图像必须在预期的路径中并且必须是不带扩展名的名称。后端代码指定:

image = Gtk.Image.new_from_gicon(
    Gio.Icon.new_for_string(
        str(cbook._get_data_path('images',
                                 f'{image_file}-symbolic.svg'))),
    Gtk.IconSize.LARGE_TOOLBAR)

所以我可以拍一张 svg 图像并将它放在我上面给出的路径中,最后附加 -symbolic 并让它工作。但是,有没有办法在不同于提供给后端的默认目录的路径中执行此操作?我目前使用的代码如下:

from matplotlib.backends.backend_gtk3 import NavigationToolbar2GTK3

class MyToolbar(NavigationToolbar2GTK3):
  def __init__(self, figure_canvas, window):
    self.toolitems = ( 
        ('Home', 'Reset original view', 'home', 'home'),
        ('Back', 'Back to  previous view', 'back', 'back'),
        ('Forward', 'Forward to next view', 'forward', 'forward'),
        (None, None, None, None),
        ('Pan', 'Pan axes with left mouse, zoom with right', 'move', 'pan'),
        ('Zoom', 'Zoom to rectangle', 'zoom_to_rect', 'zoom'),
        ('Subplots', 'Configure subplots', 'subplots', 'configure_subplots'),
        (None, None, None, None),
        ('Save', 'Save the figure', 'filesave', 'save_figure'),
        )

    NavigationToolbar2GTK3.__init__(self, figure_canvas, window)

self.navigation_toolbar = MyToolbar(self._gtkFigure, main)
self.navigation_toolbar.update()

我的预期是某些计算机上出现的断开链接是 cbook._get_data_path(由后端使用)由于某种原因出现不同的结果,所以如果我能以某种方式在脚本中更改它,也许我可以解决这个问题?如有任何帮助或指点,我们将不胜感激!

编辑:进一步挖掘后,cbook 中的 _get_data_path 似乎只是对 matplotlib.get_data_path() 的调用。来自 here it doesn't appear using a custom data path is possible in matplotlib (I was looking for a .set_data_path() method). One of the contributors suggests "grab the native tk widgets and perform the right calls to iconphoto() and friends on them." Since I am not using the Tkinter backend I am still not sure how to proceed. I am fairly certain that the method I outlined above will not work, and another method is required, similar to here.

所以最初的问题是在某些 Windows 计算机(不是全部)上,matplotlib 导航工具栏的本机图像显示为断开的链接。使用 self.toolitems 时,您只能指定图像名称。这是为什么?那么 GTK matplotlib 后端有:

image = Gtk.Image.new_from_gicon(
    Gio.Icon.new_for_string(
        str(cbook._get_data_path('images',
                                 f'{image_file}-symbolic.svg'))),
    Gtk.IconSize.LARGE_TOOLBAR)

所以文件扩展名已经在后台指定了。我的预期是 cbook._get_data_path 在出现断开链接的 Windows 计算机上产生不同的路径(而不是出现断开链接的计算机)。如前所述,cbook._get_data_path 本质上是对 matplotlib.get_data_path() 的调用,可以在代码中使用它来匹配它起作用和不起作用的计算机上的路径。在 matplotlib API 我们有:

def get_data_path():
    """Return the path to Matplotlib data."""
    return str(Path(__file__).with_name("mpl-data"))

问题是两者返回的路径相同。所以这似乎暗示问题出在 GTK 后端本身。我在某处读到某些计算机对 SVG 图像有问题,因此您应该改用 PNG 图像。我更改了 GTK 后端以反映这一点,这解决了问题:

f'{image_file}-symbolic.svg' -> f'{image_file}.png'

显然,我认为编辑 matplotlib GTK 后端脚本不是最好的主意。其他一些人建议简单地获取 PNG 文件,将它们重命名为 SVG 文件,然后用这些文件替换 mpl-data 中的原始文件。这也显得草率。我不确定最好的方法是什么,但现在我已经开始工作了,这就足够了。