I'm trying to display an image (a N*P numpy array) in a while loop with imshow but it doesn't seem to work.
When I just use "plt.imshow(image,cmap='gray')" with no indent it works perfectly.
However, when I try to use it from a while loop like
continue=True
while continue:
plt.imshow(image,cmap='gray')
continue=input()
or
i=0
while i<10:
plt.imshow(image,cmap='gray')
i+=1
the pyplot window just freeze and python crash (same problem with a if).
I don't understand why it does this, does anybody here knows? Thanks alot in advance :)
EDIT : I try to use it like this in my program
import matplotlib.pyplot as plt
import numpy as np
import PIL.Image as im
image=np.array(im.open("Blabla.jpg").convert('L')).astype(np.float32)
plt.imshow(image,cmap='gray') #This works -> ONLY when there is not a while after
keepGoin = True #But this doesn't
while keepGoin:
plt.imshow(image,cmap='gray')
keepGoin=input()
EDIT 2 :
I made a mistake : it seems that imshow pauses when a while//if is used, even if the while loop is right after the imshow. And when the while loop ends, an image is finally displayed. Maybe using this kind of loop simply pauses the process ?
So I tried to use a secondary function aiming to display the image "out" of the while but it doesn't work either, the result is the same : the pyplot window freeze during the while loop, and the image is displayed right after the loop ends.
EDIT 3 :
So after some more tries, I am pretty sure the problem is not calling imshow from a while but the fact that the loop pauses the execution of pyplot, even if it is called BEFORE the loop (If I call imshow and then use a loop, the pyplot window freeze until the loop ends)
According to some new research I've made, plt.pause could help me but I've an error when I try this.
Here are some observations which might help you debug. The code and statements below only apply to Python 2.x.
Using the code below, you would have to type the word True or False on the console from which you started the program, for it to not crash after the first showing, because input() expects some sort of input and throws EOF if you do not give it anything.
import matplotlib.pyplot as plt
import numpy as np
import PIL.Image as im
image=np.array(im.open("Blabla.jpg").convert('L')).astype(np.float32)
plt.ion()
plt.imshow(image,cmap='gray')
keepGoin = True #But this doesn't
while keepGoin:
plt.imshow(image,cmap='gray')
keepGoin=input()
If you change it to raw_input, it is more forgiving in terms of not crashing with EOF but will still terminate unless you give it some input. However, changing the loop to be independent of the input paused it for me until I pushed Enter on the terminal.
while True:
plt.imshow(image,cmap='gray')
raw_input()
If you are using a Spider the easier way is configure to show the image in console because in the console the image not freeze.
To configure the spider to show the image on console:
preferences -> python console -> graphics -> output graphic -> here: choice inline instead of automatic
Related
I have an ipywidgets.interact slider bar on a long-ish running process. This creates a situation where, when I move the slider bar, several values get buffered and I sit and wait for a while for the output to "catch up" to the point to which I've moved the slider bar. I'd like to set the number of values that get buffered when I use the slider bar.
Example:
from ipywidgets import interact
import matplotlib.pyplot as plt
import cv2
from skimage import io
image = io.imread('https://www.wikipedia.org/portal/wikipedia.org/assets/img/Wikipedia-logo-v2.png')
#interact
def edges(low=100, high=150, aperture=3):
plt.imshow(cv2.Canny(image, low, high, apertureSize=aperture))
Try moving the slider around and watch the image continue updating for a while after you stop. I'm on a laptop, so your mileage may vary if you have a beast of a machine.
How can I set the "framerate" to the interact function?
The continuous_update setting is what you want to disable for the sliders. However, I'm not 100% sure you can use it with the simple decorator approach though? Did you try this:
from ipywidgets import interact
import matplotlib.pyplot as plt
import cv2
from skimage import io
image = io.imread('https://www.wikipedia.org/portal/wikipedia.org/assets/img/Wikipedia-logo-v2.png')
#interact(continuous_update=False)
def edges(low=100, high=150, aperture=3):
plt.imshow(cv2.Canny(image, low, high, apertureSize=aperture))
I tried it and it works without saying there is an issue with the #interact(continuous_update=False) line. However, I'm not seeing it be slow without it, and so it is hard to test it is having the desired effect.
It is available for your sliders for sure if you define them yourself and not use the #interact route to handle giving you the sliders automatically.
I'm working with matplotlib plotting and use ioff() to switch interactive mode off to suppress the automatic opening of the plotting window on figrue creation. I want to have full control over the figure and only see it when explicitely using the show() command.
Now apparently the built-in commands to clear figures and axes do not work properly anymore.
Example:
import numpy as np
import matplotlib.pyplot as mpp
class PlotTest:
def __init__(self,nx=1,ny=1):
# Switch off interactive mode:
mpp.ioff()
# Create Figure and Axes:
self.createFigure(nx, ny)
def createFigure(self,nx=1,ny=1):
self.fig, self.axes = mpp.subplots(nx,ny)
if nx*ny == 1:
self.axes = np.array([self.axes])
def linePlot(self):
X = np.linspace(0,20,21)
Y = np.random.rand(21)
self.axes[0].plot(X,Y)
P = PlotTest()
P.linePlot()
P.fig.show()
Now I was thinking I could use P.fig.clear() any time to simply clear P.fig, but apparently that's not the case.
Writing P.fig.clear() directly into the script and execute it together it works and all I see is an empty figure. However that's rather pointless as I never get to see the actual plot like that.
Doing P.fig.clear() manually in the console does not do anything, regardless if the plot window is open or not, all other possible commands fail as well:
P.fig.clf()
P.axes[0].clear()
P.axes[0].cla()
mpp.clf()
mpp.cla()
mpp.close(P.fig)
Wrapping the command into a class method doesn't work either:
def clearFig(self):
self.fig.clear()
EDIT ================
After a clear() fig.axes is empty, yet show() still shows the old plot with the axes still being plotted.
/EDIT ================
Is it because I switched off interactive mode?
If you add a call to plt.draw() after P.fig.clear() it clears the figure. From the docs,
This is used in interactive mode to update a figure that has been altered, but not automatically re-drawn. This should be only rarely needed, but there may be ways to modify the state of a figure with out marking it as stale. Please report these cases as bugs.
I guess this is not a bug as you have switched off interactive mode so it is now your responsibility to explicitly redraw when you want to.
You can also use P.fig.canvas.draw_idle() which could be wrapper in the class as clearFigure method.
I'm trying to handle some events to perform user interactions with embedded subplots into a Tkinter frame. Like in this example
Works fine with "key_press_event" and "button_press_event", but does not work with "pick_event".
I modified that example from the link, just adding the following piece of code after the mpl_connect calling:
def on_button_press(event):
print('you pressed mouse button')
canvas.mpl_connect('button_press_event', on_button_press)
def on_pick(event):
print('you picked:',event.artist)
canvas.mpl_connect('pick_event', on_pick)
Why "pick_event" doesn't work into embedded graphs? And how do get it to work?
My configurations detailed:
Windows 10
Python 3.5 (conda version)
Matplotlib 1.5.3 installed via pip
Thanks in advance!
Well, I solved it...
Most events we just need to use mpl_connect method to the magic happen. My mistake is that I didn't notice that we need to say explictly that our plot is "pickable" putting a argument picker=True to only triggers the event if clicked exacly into the artist, and picker=x where x is an integer that is the pixel tolerance for the trigger. So beyond the changes I inserted for pick in the question, we should replace
a.plot(t, s) for a.plot(t, s,picker=True) or a.plot(t, s,picker=10), e.g.
I've been struggling to achieve something that is trivial in Octave: to produce a series of plots, that change when I hit a key. Here's my octave code sample.
x = [1:10];
for c=1:3
plot(x,c.*x);
hold off;
input('a');
end
When I try to do the same in python, I realized that python matplotlib has the save function, which puts it in non-blocking mode, and so I have to close the figure using a mouse, for the next figure to be produced. And the next figure is at a random other location on the screen. How can I get python to imitate the above behavior? I've tried various combinations of ion(), ioff(), plt.show(), plt.draw(), but haven't succeeded.
You can do something fancier if you want, using mpl_connect
First import pylab
from pylab import *
Then define an updateData function that can be connected to the figure canvas.
i = 1
def updateData(event):
global i,x
i +=1
y = i*x
data.set_data(x,y)
ylim(y[0],y[-1])
draw()
i and x are global variables in this case. (This could be treated in better way, this is just an example!)
Then, create you plot and connect with your defined function.
f = figure()
data, = plot(x,x)
i=1
f.canvas.mpl_connect("key_press_event",updateData)
show()
Whenever you hit any key in the keyboard (When the figure window is selected) the function updateData is called, i is incremented and the plot updated.
Have fun!
Is there a way to close a pyplot figure in OS X using the keyboard (as far as I can see you can only close it by clicking the window close button)?
I tried many key combinations like command-Q, command-W, and similar, but none of them appear to work on my system.
I also tried this code posted here:
#!/usr/bin/env python
import matplotlib.pyplot as plt
plt.plot(range(10))
def quit_figure(event):
if event.key == 'q':
plt.close(event.canvas.figure)
cid = plt.gcf().canvas.mpl_connect('key_press_event', quit_figure)
plt.show()
However, the above doesn't work on OS X either. I tried adding print statements to quit_figure, but it seems like it's never called.
I'm trying this on the latest public OS X, matplotlib version 1.1.1, and the standard Python that comes with OS X (2.7.3). Any ideas on how to fix this? It's very annoying to have to reach for the mouse every time.
This is definitely a bug in the default OS X backend used by pyplot. Adding the following two lines at the top of the file switches to a different backend that works for me, if this helps anyone else.
import matplotlib
matplotlib.use('TKAgg')
I got around this by replacing
plt.show()
with
plt.show(block=False)
input("Hit Enter To Close")
plt.close()
A hack at its best, but I hope that helps someone
use interactive mode:
import matplotlib.pyplot as plt
# Enable interactive mode:
plt.ion()
# Make your plot: No need to call plt.show() in interactive mode
plt.plot(range(10))
# Close the active plot:
plt.close()
# Plots can also be closed via plt.close('all') to close all open plots or
# plt.close(figure_name) for named figures.
Checkout the "What is interactive mode?" section in this documentation
Interactive mode can be turned off at any point with plt.ioff()
When you have focus in the matplotlib window, the official keyboard shortcut is ctrl-W by this:
http://matplotlib.org/1.2.1/users/navigation_toolbar.html
As this is a very un-Mac way to do things, it is actually cmd-W. Not so easy to guess, is it?
If you are using an interactive shell, you can also close the window programmatically. See:
When to use cla(), clf() or close() for clearing a plot in matplotlib?
So, if you use pylab or equivalent (everything in the same namespace), it is just close(fig). If you are loading the libraries manually, you need to take close from the right namespace, for example:
import matplotlib.pyplot as plt
fig = plt.figure()
plt.plot([0,1,2],[0,1,0],'r')
fig.show()
plt.close(fig)
The only catch here is that there is no such thing as fig.close even though one would expect. On the other hand, you can use plt.close('all') to regain your desktop.