Change icon in a Matplotlib figure window - python

Is it possible to change the icon of a Matplotlibe figure window? My application has a button that opens a Figure window with a graph (created with Matplotlib). I managed to modify the application icon, but the figure window still has the 'Tk' icon, typical of Tkinter.

I solved it in this way:
BEFORE I press the button that creates the figure with imshow() and show(), I initialize the figure in this way:
plt.Figure()
thismanager = get_current_fig_manager()
thismanager.window.wm_iconbitmap("icon.ico")
so when I press show() the window has the icon I want.

For me the previous answer did not work, rather the following was required:
from Tkinter import PhotoImage
import matplotlib
thismanager = matplotlib.pyplot.get_current_fig_manager()
img = PhotoImage(file='filename.ppm')
thismanager.window.tk.call('wm', 'iconphoto', thismanager.window._w, img)

Just adding this here, now that the Qt5Agg backend has made it's way into the mainstream. It's similar (pretty much the same) to the Qt4Agg backend as outlined by Sijie Chen's answer.
import os
import matplotlib.pyplot as plt
from PyQt5 import QtGui
# Whatever string that leads to the directory of the icon including its name
PATH_TO_ICON = os.path.dirname(__file__) + '/static/icons/icon.ico'
plt.get_current_fig_manager().window.setWindowIcon(QtGui.QIcon(PATH_TO_ICON))

If you are using Qt4Agg backend, the following code may help you:
thismanager = plt.get_current_fig_manager()
from PyQt4 import QtGui
thismanager.window.setWindowIcon(QtGui.QIcon((os.path.join('res','shepherd.png'))))

I found that under OS X with PyQT5, doing plt.get_current_fig_manager().window.setWindowIcon() has no effect. To get the dock icon to change you have to call setWindowIcon() on the QApplication instance, not on the window.
What worked for me is:
QApplication.instance().setWindowIcon(QtGui.QIcon(icon_path))
Do mind that QApplication.instance() will be None until you have actually created a figure, so do that first.

Related

Matplotlib: how to make the background transparent on Windows

I need the whole plot window to be transparent so that a chrome window, for example, on my desktop could be seen through the plot, so that I can add points to it while seeing what's behind it.
https://stackoverflow.com/a/45505906/13650485
The answer I've listed above is EXACTLY what I want to do, except my interactive system doesn't work with TK. I'd like to use Qt5Agg. When I run the code above, the system won't accept it -- it says QT5 is currently running. If I run it without QT already loaded, it creates a blank transparent window (yay!) but if I move it or click on the icon it turns opaque black without any plot. If I change tk to Qt5 it complains on lift. If I remove the "win" code, it has no transparency(obviously). I've tried adding everything I can think of to make the canvas transparent and I can change the color but not make it transparent.
import matplotlib
# make sure Tk backend is used
matplotlib.use("TkAgg")
import matplotlib.pyplot as plt
# create a figure and some subplots
fig, ax = plt.subplots(figsize=(4,2))
ax.plot([2,3,5,1])
fig.tight_layout()
win = plt.gcf().canvas.manager.window
win.lift()
win.attributes("-topmost", True)
win.attributes("-transparentcolor", "white")
plt.show()
When I made the changes suggested by: eyllanesc
I found within a vanilla Spyder 4.1.3 | Python 3.7.7 64-bit | Qt 5.9.6 | PyQt5 5.9.2 | Windows 10
In order to import QtCore I had to first
conda install pyqt
not enough, so then conda install pyqt5
and also conda update --all
When I did that, the code ran without errors. This is a better first result!, but I still only get the frozen mpl.fig window. This time, however, it is white. . . The console returns, but the mpl window hangs. Run again, a new frozen window. Restart and run again: same result.
I hope that this is a simple error; please teach this newby.
#eyllanesc
Revised: Python screen tracing application – needs a mostly transparent plot window.
I need the whole plot window to be transparent so that a chrome window, for example, on my desktop could be seen through the plot, so that I can add plot (x, y) points to it while seeing what's behind it.
Adding the command win.setWindowFlags(QtCore.Qt.FramelessWindowHint) did indeed make the window transparent, but it made the tool bar transparent, got rid of the title bar, and removed the ability to move or resize the window. It also made it so that the graph area was not sensitive to the mouse unless I was over the line. I added the facecolor attribute to the subplots command so I could see what was going on. As long as I put a non-zero value for either the fig-alpha or the ax-alpha, the graph is sensitive to the mouse over the whole area.
I need to be able to move and resize the window and would like to have the toolbar be opaque or at least sensitive to the mouse over the whole toolbar. Can you help with this? Thanks for past help!
## Python Code Fragment by Helen for Windows 10
## to test sequence creating plot with transparent
## background (to be used to trace and record xy pairs)
from PyQt5 import QtCore
import matplotlib
matplotlib.use("Qt5Agg") #define backend, must be before pyplot is imported
import matplotlib.pyplot as plt
# create a figure and a subplot
fig,ax = plt.subplots(figsize=(4, 2),facecolor=(1.,1.,0.,0.1)) #facecolor of figure
fig.patch.set_alpha(0.1)
ax.patch.set_alpha(0.1)
# plot some fixed points
ax.plot([2, 3, 5, 1])
fig.tight_layout()
#make window transparent to the desktop
win = plt.gcf().canvas.manager.window
win.setAttribute(QtCore.Qt.WA_NoSystemBackground, True)
win.setAttribute(QtCore.Qt.WA_TranslucentBackground, True)
win.setStyleSheet("background:transparent")
win.setWindowFlags(QtCore.Qt.FramelessWindowHint)
win.setWindowTitle("My App")
plt.show()
You have to use the Qt flags, tested on Linux:
from PyQt5 import QtCore
import matplotlib
# make sure Tk backend is used
matplotlib.use("Qt5Agg")
import matplotlib.pyplot as plt
# create a figure and some subplots
fig, ax = plt.subplots(figsize=(4, 2))
fig.patch.set_alpha(0.0)
ax.patch.set_alpha(0.0)
ax.plot([2, 3, 5, 1])
fig.tight_layout()
win = plt.gcf().canvas.manager.window
win.setAttribute(QtCore.Qt.WA_NoSystemBackground, True)
win.setAttribute(QtCore.Qt.WA_TranslucentBackground, True)
win.setStyleSheet("background:transparent")
plt.show()

Unintended widget popup in a PyQt5 program and I don't know how to fix it

So I was able to successfully embed matplotlib into my PyQt5 program, except I am running into a problem where it seems the code I have is causing a popup of a matplot widget to open and close during the generation of the matplot for the widget. I was able to source the problem, but I am stuck on how I can go about to fix it.
def getHexabinData(self, shotsDf):
#returns the object type of the shot / makes hexabin
shotsHex = plt.hexbin(-shotsDf.LOC_X, shotsDf.LOC_Y,
extent=(-250, 250, 422.5, -47.5), cmap='Blues', gridsize=45, marginals=True, visible=False)
print('done')
#grabs object of hexabin of all shots
makeDf = shotsDf[shotsDf.SHOT_MADE_FLAG == 1]
#grabs the data frame of all the makes
makesHex = plt.hexbin(-makeDf.LOC_X, makeDf.LOC_Y,
extent=(-250, 250, 422.5, -47.5), cmap=plt.cm.Reds, gridsize=45, marginals=True, visible=False)
print('done')
plt.close()
#close the hexabin plot
pctsByHex = np.true_divide(makesHex.get_array(), shotsHex.get_array())
pctsByHex[np.isnan(pctsByHex)] = 0 # convert NAN values to 0
sizesByHex = len(shotsHex.get_array()) * [0]
sizesByHex = self.getSizeHexByZone(shotsDf, sizesByHex)
sizesByHex = sizesByHex * 120
#size 210 for figsize(12,11)
print('hexes done')
return shotsHex, pctsByHex, sizesByHex
And so, I've sourced the problem to be in the function above, which is a function of a separate class in a separate file that uses the following module instead of:
import matplotlib.pyplot as plt
#instead of these imported modules below for the pyqt5 program
from matplotlib.patches import Circle, Rectangle, Arc
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import (
FigureCanvasQTAgg as FigureCanvas,
NavigationToolbar2QT as NavigationToolbar)
Apologies if this question is way too specific of a problem. I've tried to do:
plt.close()
plt.hexabin(....visible=False)
but I still get this random "matplot" widget popup that opens and closes itself until the matplot widget shows the updated plot. Is there any fix to this or something I am not seeing?
Do not use import matplotlib.pyplot as plt when you integrate Matplotlib in PyQt. The pyplot module has its own event loop and maintains its own list of windoww. This clashes with PyQt as you are now are experiencing.
So remove the plt.close() statement. Instead just close the Qt window when needed.
A good example on how to integrate without using pyplot can be found here.

Tkinter/matplotlib multiple active windows on osx

I have a script as follows that executes on my windows machine
import matplotlib.pyplot as plt
import numpy as np
import tkinter
class main(tkinter.Frame): #main window
def __init__(self, root): # initialise
tkinter.Frame.__init__(self)
self.root = root
tkinter.Button(self, text='New spots', command=self.newSpots).grid()
def newSpots(self):
x = np.random.rand(10)
y = np.random.rand(10)
plt.scatter(x,y)
plt.show()
if __name__=='__main__':
root = tkinter.Tk()
app = main(root).grid()
root.mainloop()
When running on windows, it opens a window with a simple button, and clicking this button opens a matplotlib viewer with 10 dots plotted in random positions. Each subsequent press of the button adds a further ten dots.
Executing this code on a mac produces the same initial window, and the first press of the button generates the plot and opens the viewer as expected. However, it then becomes impossible to interact with the original window (only the controls on the viewer work) until the viewer window is closed. How do I make the behaviour on the mac mirror that on the windows machine?
I found a solution to this issue -- it seems matplotlib defaults to the TkAgg backend on Windows (I'm unsure whether this is a general Windows thing, or specific to whatever particular install is on the machine).
Adding the following lines to the top of the script forces the TkAgg backend and leads to the same behaviour on both machines.
import matplotlib
matplotlib.use("TkAgg")

How to embed vispy graph in PyQt?

I'm trying to embed a vispy plot (more specifically, a Vispy SceneCanvas) as a QWidget into PyQt4. I would presume the answer would be something like this:
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import vispy.mpl_plot as plt
app = QApplication(sys.argv)
win = QMainWindow()
plt.plot([1,2,3,4], [1,4,9,16])
vispyCanvas=plt.show()[0]
win.setCentralWidget(vispyCanvas)
However, when I try this the last line gives me the expected error that vispyCanvas is type SceneCanvas and not of type QWidget. When I print(vispyCanvas), it prints out <Vispy canvas (PyQt4 (qt) backend) at 0x142bcb00L>, which is why I suspect that it should be possible to treat it or one of its attributes as a QWidget object.
The answer is simple:
win.setCentralWidget(vispyCanvas.native)
As long as vispy is using Qt as its backend, then Canvas.native refers to the underlying QGLWidget.

OSX How to bring Matplotlib window to the front?

I'm trying to use matplotlib for chart visualizations, but it is very annoying to look for a window each time I run the project. Is there any way to force it to be on top of other windows? I use OSX 10.8 and PyCharm IDE and already tried
from pylab import get_current_fig_manager()
get_current_fig_manager().window.raise_()
Which fails with
AttributeError: 'FigureManagerMac' object has no attribute 'window'
I'd appreciate any other ideas.
you're call to window.raise_() is from PyQT.
Indeed, you can raise the window in this way but you need to:
set PyQT4 as your backend before you do any other business with matplotlib
And
import matplotlib
matplotlib.use('Qt4Agg')
Either you fix you import statement (remove the brackets) or save yourself the import and access the window through the figure
with
window = fig.canvas.manager.window
Only then you can call window.raise_() and the window will be in front of pycharm.
This works for me from IPython:
from pylab import get_current_fig_manager
fm = get_current_fig_manager()
fm.show()
I haven't found a case in which show() doesn't work by itself, though.
[cphlewis] had a great answer. I found myself doing this so often that I def a little function to pop all my windows up to the surface:
def pop_all():
#bring all the figures hiding in the background to the foreground
all_figures=[manager.canvas.figure for manager in matplotlib.\
_pylab_helpers.Gcf.get_all_fig_managers()]
[fig.canvas.manager.show() for fig in all_figures]
return len(all_figures)

Categories