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.
Related
I have been trying to understand the matplotlib interactive figure documentation and links therein as part of several days of research into trying to understand how to draw my matplotlib plots. Some of my lack of understanding I put down to poor familiarity with the concepts and phrases.
However, one thing that completely escapes me is the difference between the event loop integration and interactive mode. Quoting the documentation:
The GUI event loop being integrated with your command prompt and the figures being in interactive mode are independent of each other.
They explain this futher:
If you use pyplot.ion but have not arranged for the event loop integration, your figures will appear but will not be interactive while the prompt is waiting for input. You will not be able to pan/zoom and the figure may not even render
I understand this event loop integration to be implemented using plt.pause() or FigureCanvasBase.flush_events(), something that would allow "communication": a GUI event loop. Indeed my experience in spyder has been that my figures in a loop in a class are not drawn at all unless I use plt.pause() (flush doesn't work). However, just above this, they seem to contradict this statement when listing the behavior of interactive figures:
newly created figures will be displayed immediately & figures will automatically redraw when elements are changed
Even looking at the accepted answer to this related question, the figure is not drawn in interactive mode until plt.pause(.1) is called. The explanation therein confuses things more:
This means that a figure can be drawn inside a GUI without starting the GUI event loop.
This is wrong because the documentation states that plt.pause() DOES cause an event loop:
pyplot.pause - Run the GUI event loop for interval seconds.
However that answer does give me the idea that a main difference, despite the documentation wording is that interactive mode makes it so that plt.show() does not cause blocking and allows the script to still run while the figures are open. The answer also suggests to me that interactive does not mean responsive and that ironically blocking during a non-interactive plt.show() or timed plt.pause() is the only time where figures become responsive.
the disadvantage is that you do not have an event loop - hence the GUI may quickly become unresponsive and you are responsible yourself for letting it manage events.
Perhaps this is why I cannot resize, minimize, close , or plt.close('all') my figures even after my script stops even after using plt.ion (though this will be a future question to explore elsewhere). This debunks my earlier hypothesis that interactivity functions as a way to for users to "push buttons" (to be very coloquial) on the plot at any time rather than during times when the plt.pause() or plt.show() had blocked the script and the interactivity turned on temporarily.
Any help with these contradictory statements about the roles of command prompt integration and interactivity would be greatly appreciated.
I am writing a python program to do some data analysis, and while developing the code, I have notived that if I do plt.show() at the end of my code, the windows stay on forever unless I manually close each one.
I would like to be able to
1. Either close the old plot when I rerun the program, i.e. at the beginning of each execution, the program should check for any pyplot instances running and close them, or
2. Update the existing figures with the new data, although this would be the less favorable solution, since I am also changing plot types and am unsure how that will affect the replotting.
For the first choice I have tried plt.close('all') at various locations in my code but it either does nothing or immedeately closes the window after it is being shown.
I have also seen people suggesting to just kill the associated process. How would I do that from within the python program?
Any help would be appreciated
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.