I've recently switched to pycharm as my main development environment for python and in general I'm quite happy with how it works. However I encountered some problems. First of all I find running script quite slow, not to mention if I show a plot using matplotlib then the interactive plot is quite slow compared to simply using IDLE.
I thought about solving this by not actually showing a plot, but rather just saving the figure. However it seems that even if I don't explictily call show() that is called in the background and then closed again. Any idea what is going on?
My code:
# plot exchange rate over the years
fig, ax = plt.subplots(1, 1, figsize=(12,9))
ax.plot(years, data, color=c[0])
# set figure properties
ax.set_title('Rate')
ax.set_xlim([min(years), max(years)])
ax.set_ylabel('Rate per x')
ax.set_xlabel('Source: '+source, horizontalalignment='right', x=1.0, fontsize=9)
ax.xaxis.set_ticks(years[::2])
fig.savefig('rate.png', dpi=144, bbox_inches='tight')
plt.close(fig)
My pycharm installation details:
PyCharm 2017.3.2 (Community Edition)
Build #PC-173.4127.16, built on December 18, 2017
JRE: 1.8.0_152-release-1024-b8 amd64
JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
Windows 7 6.1
Any idea how I can at least switch off the opening of the interactive gui for a plot (even if I'm not calling show())? This would already help a lot. If there are ways to make it all faster that would be even beter.
Your matplotib could be using an interactive backend. This means that interactive mode will be enabled by default.
Therefore, as soon as you plot anything, the figure window will open and your script will continue to do whatever is next. Upon reaching the end of the script, the window will close. If the plotting of your figure is at the end of the script the window will appear to open then immediately close. You can test this by putting input() at the very end of your script and the window should stay open.
In order to fix this, you can turn interactive mode off using
plt.ioff()
In which case, calling (or not calling) plt.show() will work as expected.
Related
I want to show plots in a separate window. Currently I have the IPython graphics backend set to "automatic".
When I re-run the code (or plot another figure), Spyder opens a new plot window. Is it possible to refresh the figure in the window that is already opened instead of opening a new one?
The GUI window that opens when you call plt.show() is bound to a figure. You cannot change the figure inside it. (Well, to be precise, there might be an option of obtaining a handle from the operating system and manipulating its content, but I assume this is not worth the effort.)
Re-running the code actually means that you produce a new figure since the code does not know that it's been run before.
So, exchanging the figure or reusing the window to plot a different figure is not possible.
What is possible however is to use the figure and manipulate the figure while it's open. This is done via plt.ion(). After calling this command in IPython you can adapt the figure, e.g. adding new lines to it etc.
See this example:
At IN [6] the window opens and when IN [7] is executed, the figure stays open and the content changes.
Sure, it is possible with Spyder while in the same running kernel. Try the following example using num as parameter to plt.figure(), where num will always refer to the same figure and refresh it if already opened. Also works with plt.subplots().
import matplotlib.pyplot as plt
from scipy import *
t = linspace(0, 0.1,1000)
w = rand(1)*60*2*pi
fig = plt.figure(num=10, clear=True, figsize = [10,8])
plt.plot(t,cos(w*t))
plt.plot(t,cos(w*t-2*pi/3))
plt.plot(t,cos(w*t-4*pi/3))
I've recently built a python script that interacts with an Arduino and a piece of hardware that uses LIDAR to map out a room. Everything works great, but anytime you click on the plot that is generated with maptotlib, the computer freaks out and crashes the script that is running. This is partly because I was given a $300 computer to run this on, so it's not very powerful. However, I feel like even a $300 computer should be able to handle a mouse click.
How can I ignore mouse clicks entirely with matplotlib so that the computer doesn't freak out and crash the script?
If that's not the correct solution, what might be a better solution?
Edit: This is an interactive plotting session (sort of, I just replace the old data with the new data, there is no plot.ion() command called). So, I cannot just save the plot and show it. The Arduino transmits data constantly.
You can try bypassing the click event on your plot:
import matplotlib.pyplot as plt
fig = plt.figure()
plt.axes(xlim = (0, 3), ylim = (0, 3))
def onclick(event):
pass
fig.canvas.mpl_connect('button_press_event', onclick)
plt.show()
, but I doubt this will work. What I recommend as a solution (if the stuff above does not work) is to make your plot and save it to file (without showing it):
plt.savefig('fname.png')
plt.close()
Than make python open the image (using subprocess for example) with whatever external tool you prefer in your OS.
I'm saying this because I suspect you might have some kind of packages incompatibility that is causing your script to crash (maybe a backend from mpl or whatever other library you are using over mpl). If this is the case more information is needed to try solving the issue.
I feel that this might be more easily resolved by altering the hardware - can you temporarily unplug the mouse, or tape over the track pad to stop people fiddling with it?
I suggest this because your crashing script will always process mouse-clicks in some way, and if you don't know what's causing the crashes then you may be better off just ensuring that there are no clicks.
Is there any way to show a pyplot figure in Python 2.65, Matplotlib 0.99, without locking everything else?
I have a program with a Pmw GUI running on Python 2.75 with Matplotlib 1.3.1. on Windows (64-bit Winpython).
Everytime a figure is drawn (or everytime something is added to an existing one), the routine calls plt.show().
It is possible to show pyplot figures while allowing the user to keep using the GUI and manipulate the figures, nothing blocks anything, as I want it to be since I need the user to look at the plots when deciding what to do next in the GUI, and to have several plots next to each other for comparison.
Now, I need to make all of this work on a system with Python 2.65 and Matplotlib 0.99. The behaviour now seems to be that nothing is visible unless plt.show() is called, and then it will block everything until the plot window is closed.
I tried using plt.draw() instead but then the figure does not even show up.
Worse: Some routines who draw into existing figures never get a chance because they can't execute while the figure is being shown, and when they can, the figure is gone already. I cannot wait until the last drawing operation because the graphs are meant to build up incremental, adding information to existing graphs which the user needs to be able to see.
I am not allowed to update matplotlib. I am allowed to use non-binary parts of libraries if I make them part of "my" software package.
Ideally, I am looking for code that will work in both environments I'm working in, but at this point I am willing to make compromises...
Update:
I have found some code running in the same environment that is able to do all of these things, where I can remove the plt.show() calls, even run it in IDLE (which according to matplotlib docs has problems in these regards), and it "just works" -- I haven't been able to find any difference in how the two codes handle the task: Both define a figure.axes object, pass it to routines that draw into them (using plt.plot()) and store it for future use.
I've also found that my current code will change its behaviour on the current set of libraries, depending on how I run it: In a "regular" console in Spyder or a system console, all's fine, but on a dedicated console in Spyder, the first plot will lock up the interface
=> I'm beginning to think this isn't about the matplotlib version after all, but have no idea where else to look --is there anything else that changes matplotlib's behaviour, based on how it's launched?
It looks like you are looking for:
plt.show(block=False)
or plt.ion:
plt.ion()
plt.show()
# update figure, calc stuff
plt.pause()
Not really sure if they are available in 0.99.
elyase's answer sent me into the right direction:
import matplotlib
matplotlib.interactive(True)
This at the beginning of a script is what it takes to make sure that matplotlib will always and in all environments create plots in a way that allows scripts to continue running, while allowing the user to manipulate the figure and the code to keep drawing into it.
Matplotlib has two modes of operating: The interactive and the non-interactive, and my script going into the latter mode was the problem.
I have still no idea why this is the default behaviour in some cases and not in others (had believed it was one standard setting per matplotlib installation). Since other scripts are able to run without the above. and there must be something that my script inadvertently does to land in non-interactive mode, but the above code is what will override the setting, come what may; at least in all scenarios I've tried so far: python 2.75, matplotlib 1.3.1 using Spyder's regular and dedicated shells and system shells, and Py 2.65, matplotlib 0.99, using system shells and IDLE.
P.S.:
This does not seem to help on Linux. I tried to run the same skript (Tkinter GUI that opens plots, is able to draw into existing plots) on SuSE 13.1 (current version of python 2.7 and all libraries) and no single plot window pops up until the GUI is closed, and then they all jump at me ... it seems that it's not trivial to make matplotlib behave the same everywhere.
I have noticed that when I run:
import pylab as pl
pl.ion()
# Plot something
pl.show()
pl.close()
The last statement does not fully close the Figure. The figure goes dark, and the contents go away, but the Figure stays on the screen until I exit IPython as shown below
I am using the latest stable version of matplotlib (1.3.1) using an Anaconda distribution, on Linux 64 bit, and I connect remotely using ssh -X.
The backend I am using is below:
backend : QT4Agg
backend.qt4 : PySide
you have to specify wich figure you want to close. In case you want to close all of them:
pl.close('all')
Also, there is a way to just clear but not close a figure:
pl.clf()
Also, seen below from another SO question:
Remember that plt.show() is a blocking function, so in the example code you used above, plt.close() isn't being executed until the window is closed, which makes it redundant.
You can use plt.ion() at the beginning of your code to make it non-blocking, although this has other implications.
You can also use the following lines after your plotting
#Your Plotting function
plt.waitforbuttonpress(0)
plt.close(fig)
The plt.waitforbuttonpress(0) will wait until a user input (Key press) is given. After that it will properly close the matplotlib window properly. It is very important to specify which figure to close.
The documentation for the "interactive mode" in Matplotlib's pyplot reads:
The interactive property of the pyplot interface controls whether a figure canvas is drawn on every pyplot command. If interactive is False, then the figure state is updated on every plot command, but will only be drawn on explicit calls to draw(). When interactive is True, then every pyplot command triggers a draw.
This seems clear enough: when the interactive mode is on, one can do plot() without having to do draw(). However, doing draw() in the following code does not do anything:
from matplotlib import pyplot as pp
# Interactive mode is off by default
pp.plot([10, 20, 50])
pp.draw()
raw_input('Press enter...') # No graph displayed?!!
(on Windows XP, Matplotlib 1.0.1).
Adding ion() at the beginning makes the figure(s) appear, while waiting for the user to type enter (which conveniently closes all the figures):
from matplotlib import pyplot as pp
ion()
pp.plot([10, 20, 50]) # No draw() is necessary
raw_input('Press enter...') # The graph is interactive *and* the terminal responds to enter
Thus, it looks like ion() does more than just adding automatic graph updates after each plotting command, and I unfortunately can't find anything in the documentation. Another, more important problem with the latter program is that ion() makes all plot commands update the graph, which is time consuming when a single graph is updated multiple times.
So, is there a way of:
having the terminal wait for enter, after which all the figures are automatically closed,
having interactive Matplotlib graphs,
… without forcing the interactive mode to be on at the beginning (so as to not force auto-updates of the graphs, which could be time consuming)?
Here is the summary of an interesting discussion on this subject in the Matplotlib mailing list. The executive summary is:
The interactive mode (activated with ion()) automates many things. In particular, pyplot.* commands automatically update on the screen the relevant axes. However, method calls on Matplotlib objects like ax.plot() (ax being an Axes object) do not normally perform automatic updates; in this case, pyplot.draw() performs the necessary update.)
The non-interactive mode is less convenient. draw() does not normally update the figure on screen. The fact that draw() is somewhat "inactive" in non-interactive mode is not mentioned in the current documentation, but will hopefully be included there soon.
In the mean time, more information on the interactive and non-interactive modes can be found in a current branch of Matplotlib. A better documentation for draw(), show() and friends can also be found in the same branch.
I would suggest that you follow the last comment of 'Thomas K'. I remember a similar question on the mailing list, but I couldn't find it after several minutes of searching. Sorry.
I had also this problem and the better easier way for me was/is to use ipython --pylab. I have a much older version of matplotlib installed which have some problems with ion(). Beside this, matplotlib had also some problems with draw() on Windows. Maybe it was fixed in the last versions.
p.s.: Sorry that I couldn't helped you really well.
Best regards.