Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

GUI icon in Tkinter #897

Merged
merged 6 commits into from

4 participants

@pelson
Collaborator

I have implemented the matplotlib icon for the Tkinter backend (so that I can differentiate it from other Tk based tools easily).

I also tried implementing the icon in wx unsuccessfully, but have left my attempt in the hope of finding a wxPython wizz who can fix it. (I will put some in-line comments in the review changes)

Having looked over the Gtk backend's icon code I also made a couple of simplifications.

Finally, before looking at the backends who have already implemented icons I didn't realise there was already a matplotlib icon, therefore I produced one based on the documentation logo. FYI you can find the icon in an earlier commit but I do not propose using it (hence I have removed it from this pull) as when scaled down to 16x16 or 32x32 it starts to look like a cd burning icon.

@pelson pelson commented on the diff
lib/matplotlib/backends/backend_wx.py
@@ -1592,7 +1599,6 @@ def destroy(self, *args):
DEBUG_MSG("destroy()", 1, self)
self.frame.Destroy()
#if self.tb is not None: self.tb.Destroy()
- import wx
@pelson Collaborator
pelson added a note

Already imported on line 67.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@pelson pelson commented on the diff
lib/matplotlib/backends/backend_wx.py
@@ -1955,11 +1961,6 @@ def set_history_buttons(self):
class NavigationToolbarWx(wx.ToolBar):
def __init__(self, canvas, can_kill=False):
- """
- figure is the Figure instance that the toolboar controls
-
- win, if not None, is the wxWindow the Figure is embedded in
- """
@pelson Collaborator
pelson added a note

Looks like it was for an older interface or was a copy&paste error as it doesn't apply to this class.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/matplotlib/backends/backend_gtk3.py
((6 lines not shown))
- self.window.set_icon_from_file(window_icon)
- except:
- # some versions of gtk throw a glib.GError but not
- # all, so I am not sure how to catch it. I am unhappy
- # diong a blanket catch here, but an not sure what a
- # better way is - JDH
- verbose.report('Could not load matplotlib icon: %s' % sys.exc_info()[1])
+ try:
+ self.window.set_icon_from_file(window_icon)
+ except (SystemExit, KeyboardInterrupt):
+ # re-raise exit type Exceptions
+ raise
+ except:
+ # some versions of gtk throw a glib.GError but not
+ # all, so I am not sure how to catch it. I am unhappy
+ # doing a blanket catch here, but an not sure what a
@WeatherGod Collaborator

"an" --> "am"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@WeatherGod WeatherGod commented on the diff
lib/matplotlib/backends/backend_gtk3.py
@@ -1048,17 +1050,14 @@ def on_dialog_lineprops_okbutton_clicked(self, button):
def on_dialog_lineprops_cancelbutton_clicked(self, button):
self.dlg.hide()
-# set icon used when windows are minimized
-try:
@WeatherGod Collaborator

why remove this exception handling? At the very least we could use the verbose.report() there to provide us information and then re-raise (or maybe add a message to the exception and let it bubble up?)

@pelson Collaborator
pelson added a note

The comment needs removing, as far as I can see, this try block will never fail.

@mdboom Owner
mdboom added a note

I actually agree that this exception handling is unnecessary -- it really shouldn't fail here, unless something is seriously wrong. This is different from the try/excepts above where if the icon can't be set we should continue along without an icon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@mdboom mdboom commented on the diff
lib/matplotlib/backends/backend_tkagg.py
@@ -78,6 +78,16 @@ def new_figure_manager(num, *args, **kwargs):
FigureClass = kwargs.pop('FigureClass', Figure)
figure = FigureClass(*args, **kwargs)
window = Tk.Tk()
+
+ if Tk.TkVersion >= 8.5:
+ # put a mpl icon on the window rather than the default tk icon. Tkinter
+ # doesn't allow colour icons on linux systems, but tk >=8.5 has a iconphoto
+ # command which we call directly. Source:
+ # http://mail.python.org/pipermail/tkinter-discuss/2006-November/000954.html
+ icon_fname = os.path.join(rcParams['datapath'], 'images', 'matplotlib.gif')
@mdboom Owner
mdboom added a note

It looks like matplotlib.gif didn't get committed. I tried changing this to .png -- it appears that Tkinter doesn't support png, so we'll need to include a gif version of the regular matplotlib icon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@mdboom
Owner

Where has this been tested? We should have someone (even if not yourself) test this for Tk, Gtk, Gtk3 and Wx under Linux, Windows and OS-X.

@pelson
Collaborator

Test matrix (I will update with people once they can confirm working):

OS Tkinter Gtk Gtk3 Wx
Linux (Ubuntu 12.04) pelson & mdboom mdboom mdboom pelson & mdboom
Windows
OS-X jkseppan jkseppan jkseppan (with a warning) jkseppan

Test process:

import matplotlib
# set the appropriate backend for your test
matplotlib.use('TkAgg')
matplotlib.use('GTKAgg')
matplotlib.use('GTK3Agg')
matplotlib.use('WXAgg')

import matplotlib.pyplot as plt
plt.plot(range(10))
plt.show()

Check the icon displays in the toolbar & in the title bar.

@mdboom
Owner

Thanks. The .gif file is still not getting installed. You need to add a line for mpl-data/images/*.gif to the package_data list in setup.py.

@mdboom
Owner

Tested (successfully) all backends on Linux.

@jkseppan
Collaborator

On OS X, under ipython, with TkAgg, I get

TclError: can't use "pyimage1" as iconphoto: not a photo image

from the line

---> 89         window.tk.call('wm', 'iconphoto', window._w, icon_img)

In pdb it does look like icon_img is a PhotoImage:

ipdb> window.tk
<tkapp object at 0x103ff1370>
ipdb> window._w
'.'
ipdb> icon_img
<Tkinter.PhotoImage instance at 0x103ff4e60>
@pelson
Collaborator

Thanks @jkseppan. I've put a try except around that line to catch the failure on some OSes.
By the way, which backends were you able to test on?

@jkseppan
Collaborator

OS X 10.6.8, Python 2.7.3 via MacPorts:

TkAgg: crashes (probably unrelated to this change)
GtkAgg: shows the X11 logo as the icon
Gtk3Agg: couldn't install pygobject
Qt4Agg: shows a yellow sine wave as the title bar icon, a box with "exec" when you press Cmd+Tab and in the dock (this is usual when you run a binary that opens a window but is not a proper application)

@jkseppan
Collaborator

Trying again, OS X 10.6.8, Python 2.7.3 via Homebrew:

GtkAgg: shows the X11 logo in the window title bar

backend GTKAgg version 2.24.0
Could not load matplotlib icon: Couldn't recognize the image file format for file '/opt/homebrew/Cellar/python/2.7.3/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib-1.2.x-py2.7-macosx-10.6-x86_64.egg/matplotlib/mpl-data/images/matplotlib.svg'

OSX, TkAgg, WxAgg: nothing in the title bar

Qt4Agg: sine wave in the title bar

The icon shown in the Dock and when you press Cmd-Tab is the Python starship icon, except with GtkAgg it's the X11 icon (which is what OS X always shows for X11.app).

Actually I'm not sure if title bar icons are the right thing on OS X. Apple's user interface guidelines says title bars can have what they call a proxy icon "after the user has given a document a name and save location for the first time", and users can drag-and-drop the icon to e.g. attach the document in an email, or cmd-click the icon to navigate the file system hierarchy up from the save location. I don't think a matplotlib plot window is a document like that - it's an interactive view into the object, and you can save a png or pdf representation of the plot, but you can't save the program state that corresponds to what's visible in the window.

One thing that would be nice is a matplotlib icon for the Dock and Cmd-Tab, but I think that's a different task altogether.

@pelson
Collaborator

Thanks @jkseppan. I didn't get that warning for GtkAgg backend (gtk 2.24 installed via homebrew on osx 10.7).

Out of interest, did you get Gtk3 and wx from homebrew? I haven't been as successful with those dependencies.

Other than perhaps addressing the warning (which I am unable to reproduce), I don't see any blockers on this, any objections?

@jkseppan
Collaborator

Sorry, I didn't mean that Gtk3 prints a warning - I meant that I couldn't install Gtk3Agg at all, because I can't find a way to install pygobject via homebrew (or MacPorts). I found someone's homebrew branch with an attempt, but it had diverged so far from mainstream homebrew that I feared it would break my Gtk3 installation. There's some information about the problems at https://trac.macports.org/ticket/33877 (basically you have to build various dependencies with --enable-introspection, but both MacPorts and Homebrew use --disable-introspection on everything, because introspection breaks something else).

I installed wxpython via brew install wxmac --python --devel and it seems to work fine.

@pelson
Collaborator

@jkseppan: It appears you are the only one who has seen any issues with this, is there any action that needs to be done? or are we at a stage where you would be happy to merge?

@jkseppan
Collaborator

I'm happy with merging this. It just doesn't show the icon on my system with GtkAgg, but it's no worse than before.

@pelson
Collaborator

@jkseppan I've rebased. Would you mind doing the merge?

@WeatherGod
Collaborator

Merging...

@WeatherGod WeatherGod merged commit 2ded37a into from
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jul 29, 2012
  1. Tkinter logo added.

    Phil Elson authored pelson committed
  2. Checked gtk backend & simplified some icon related code.

    Phil Elson authored pelson committed
  3. Removed created icons in favour of pre-existing ones. Tried, unsucces…

    pelson authored pelson committed
    …sfully to implement icon in wx.
  4. Added gif logo. Fixed typo.

    Phil Elson authored pelson committed
  5. added gifs to the package_data in setup.py.

    Phil Elson authored pelson committed
  6. @pelson

    Added a try/except to the tk icon setting.

    pelson authored pelson committed
This page is out of date. Refresh to see the latest.
View
55 lib/matplotlib/backends/backend_gtk3.py
@@ -359,15 +359,17 @@ def __init__(self, canvas, num):
self.window = Gtk.Window()
self.set_window_title("Figure %d" % num)
- if (window_icon):
- try:
- self.window.set_icon_from_file(window_icon)
- except:
- # some versions of gtk throw a glib.GError but not
- # all, so I am not sure how to catch it. I am unhappy
- # diong a blanket catch here, but an not sure what a
- # better way is - JDH
- verbose.report('Could not load matplotlib icon: %s' % sys.exc_info()[1])
+ try:
+ self.window.set_icon_from_file(window_icon)
+ except (SystemExit, KeyboardInterrupt):
+ # re-raise exit type Exceptions
+ raise
+ except:
+ # some versions of gtk throw a glib.GError but not
+ # all, so I am not sure how to catch it. I am unhappy
+ # doing a blanket catch here, but am not sure what a
+ # better way is - JDH
+ verbose.report('Could not load matplotlib icon: %s' % sys.exc_info()[1])
self.vbox = Gtk.Box()
self.vbox.set_property("orientation", Gtk.Orientation.VERTICAL)
@@ -562,12 +564,15 @@ def configure_subplots(self, button):
window = Gtk.Window()
- if (window_icon):
- try: window.set_icon_from_file(window_icon)
- except:
- # we presumably already logged a message on the
- # failure of the main plot, don't keep reporting
- pass
+ try:
+ window.set_icon_from_file(window_icon)
+ except (SystemExit, KeyboardInterrupt):
+ # re-raise exit type Exceptions
+ raise
+ except:
+ # we presumably already logged a message on the
+ # failure of the main plot, don't keep reporting
+ pass
window.set_title("Subplot Configuration Tool")
window.set_default_size(w, h)
vbox = Gtk.Box()
@@ -963,7 +968,6 @@ def get_active_line(self):
line = self.lines[ind]
return line
-
def get_active_linestyle(self):
'get the active lineinestyle'
ind = self.cbox_linestyles.get_active()
@@ -997,8 +1001,6 @@ def _update(self):
line.figure.canvas.draw()
-
-
def on_combobox_lineprops_changed(self, item):
'update the widgets from the active line'
if not self._inited: return
@@ -1044,17 +1046,14 @@ def on_dialog_lineprops_okbutton_clicked(self, button):
def on_dialog_lineprops_cancelbutton_clicked(self, button):
self.dlg.hide()
-# set icon used when windows are minimized
-try:
@WeatherGod Collaborator

why remove this exception handling? At the very least we could use the verbose.report() there to provide us information and then re-raise (or maybe add a message to the exception and let it bubble up?)

@pelson Collaborator
pelson added a note

The comment needs removing, as far as I can see, this try block will never fail.

@mdboom Owner
mdboom added a note

I actually agree that this exception handling is unnecessary -- it really shouldn't fail here, unless something is seriously wrong. This is different from the try/excepts above where if the icon can't be set we should continue along without an icon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
- if sys.platform == 'win32':
- icon_filename = 'matplotlib.png'
- else:
- icon_filename = 'matplotlib.svg'
- window_icon = os.path.join(rcParams['datapath'], 'images', icon_filename)
-except:
- window_icon = None
- verbose.report('Could not load matplotlib icon: %s' % sys.exc_info()[1])
+# Define the file to use as the GTk icon
+if sys.platform == 'win32':
+ icon_filename = 'matplotlib.png'
+else:
+ icon_filename = 'matplotlib.svg'
+window_icon = os.path.join(matplotlib.rcParams['datapath'], 'images', icon_filename)
+
def error_msg_gtk(msg, parent=None):
if parent is not None: # find the toplevel Gtk.Window
View
17 lib/matplotlib/backends/backend_tkagg.py
@@ -78,6 +78,23 @@ def new_figure_manager(num, *args, **kwargs):
FigureClass = kwargs.pop('FigureClass', Figure)
figure = FigureClass(*args, **kwargs)
window = Tk.Tk()
+
+ if Tk.TkVersion >= 8.5:
+ # put a mpl icon on the window rather than the default tk icon. Tkinter
+ # doesn't allow colour icons on linux systems, but tk >=8.5 has a iconphoto
+ # command which we call directly. Source:
+ # http://mail.python.org/pipermail/tkinter-discuss/2006-November/000954.html
+ icon_fname = os.path.join(rcParams['datapath'], 'images', 'matplotlib.gif')
@mdboom Owner
mdboom added a note

It looks like matplotlib.gif didn't get committed. I tried changing this to .png -- it appears that Tkinter doesn't support png, so we'll need to include a gif version of the regular matplotlib icon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ icon_img = Tk.PhotoImage(file=icon_fname)
+ try:
+ window.tk.call('wm', 'iconphoto', window._w, icon_img)
+ except (SystemExit, KeyboardInterrupt):
+ # re-raise exit type Exceptions
+ raise
+ except:
+ # log the failure, but carry on
+ verbose.report('Could not load matplotlib icon: %s' % sys.exc_info()[1])
+
canvas = FigureCanvasTkAgg(figure, master=window)
figManager = FigureManagerTkAgg(canvas, num, window)
if matplotlib.is_interactive():
View
39 lib/matplotlib/backends/backend_wx.py
@@ -1,8 +1,5 @@
from __future__ import division, print_function
"""
-
- backend_wx.py
-
A wxPython backend for matplotlib, based (very heavily) on
backend_template.py and backend_gtk.py
@@ -18,14 +15,17 @@
"""
-cvs_id = '$Id$'
+import sys
+import os
+import os.path
+import math
+import StringIO
+import weakref
+import warnings
-
-import sys, os, os.path, math, StringIO, weakref, warnings
import numpy as np
-
# Debugging settings here...
# Debug level set here. If the debug level is less than 5, information
# messages (progressively more info for lower value) are printed. In addition,
@@ -188,7 +188,6 @@ def __init__(self, parent, *args, **kwargs):
# Unbinding causes Wx to stop for some reason. Disabling for now.
# def __del__(self):
-# import wx
# TimerBase.__del__(self)
# self.parent.Bind(wx.EVT_TIMER, None, self._timer)
@@ -410,7 +409,6 @@ def get_gc(self):
assert self.gc != None, "gc must be defined"
return self.gc
-
def get_wx_font(self, s, prop):
"""
Return a wx font. Cache instances in a font dictionary for
@@ -448,7 +446,6 @@ def get_wx_font(self, s, prop):
return font
-
def points_to_pixels(self, points):
"""
convert point measures to pixes using dpi and the pixels per
@@ -456,6 +453,7 @@ def points_to_pixels(self, points):
"""
return points*(PIXELS_PER_INCH/72.0*self.dpi/72.0)
+
class GraphicsContextWx(GraphicsContextBase):
"""
The graphics context provides the color, line styles, etc...
@@ -627,6 +625,7 @@ def get_wxcolour(self, color):
a *= 255
return wx.Colour(red=int(r), green=int(g), blue=int(b), alpha=int(a))
+
class FigureCanvasWx(FigureCanvasBase, wx.Panel):
"""
The FigureCanvas contains the figure and does event handling.
@@ -1421,7 +1420,7 @@ def _create_wx_app():
# retain a reference to the app object so it does not get garbage
# collected and cause segmentation faults
_create_wx_app.theWxApp = wxapp
-
+
def draw_if_interactive():
"""
@@ -1512,6 +1511,15 @@ def __init__(self, num, fig):
self.Fit()
self.canvas.SetMinSize((2, 2))
+
+ # give the window a matplotlib icon rather than the stock one.
+ # This is not currently working on Linux and is untested elsewhere.
+ #icon_path = os.path.join(matplotlib.rcParams['datapath'],
+ # 'images', 'matplotlib.png')
+ #icon = wx.IconFromBitmap(wx.Bitmap(icon_path))
+ # for xpm type icons try:
+ #icon = wx.Icon(icon_path, wx.BITMAP_TYPE_XPM)
+ #self.SetIcon(icon)
self.figmgr = FigureManagerWx(self.canvas, num, self)
@@ -1559,6 +1567,7 @@ def Destroy(self, *args, **kwargs):
wxapp.Yield()
return True
+
class FigureManagerWx(FigureManagerBase):
"""
This class contains the FigureCanvas and GUI frame
@@ -1566,8 +1575,6 @@ class FigureManagerWx(FigureManagerBase):
It is instantiated by GcfWx whenever a new figure is created. GcfWx is
responsible for managing multiple instances of FigureManagerWx.
- NB: FigureManagerBase is found in _pylab_helpers
-
public attrs
canvas - a FigureCanvasWx(wx.Panel) instance
@@ -1599,7 +1606,6 @@ def destroy(self, *args):
DEBUG_MSG("destroy()", 1, self)
self.frame.Destroy()
#if self.tb is not None: self.tb.Destroy()
- import wx
@pelson Collaborator
pelson added a note

Already imported on line 67.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
#wx.GetApp().ProcessIdle()
wx.WakeUpIdle()
@@ -1939,11 +1945,6 @@ def set_history_buttons(self):
class NavigationToolbarWx(wx.ToolBar):
def __init__(self, canvas, can_kill=False):
- """
- figure is the Figure instance that the toolboar controls
-
- win, if not None, is the wxWindow the Figure is embedded in
- """
@pelson Collaborator
pelson added a note

Looks like it was for an older interface or was a copy&paste error as it doesn't apply to this class.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
wx.ToolBar.__init__(self, canvas.GetParent(), -1)
DEBUG_MSG("__init__()", 1, self)
self.canvas = canvas
View
BIN  lib/matplotlib/mpl-data/images/matplotlib.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
1  setup.py
@@ -98,6 +98,7 @@
'mpl-data/fonts/ttf/RELEASENOTES.TXT',
'mpl-data/images/*.xpm',
'mpl-data/images/*.svg',
+ 'mpl-data/images/*.gif',
'mpl-data/images/*.png',
'mpl-data/images/*.ppm',
'mpl-data/example/*.npy',
Something went wrong with that request. Please try again.