My goal is to update an image after putting it through a filter. The image is represented as a numpy Array, and displayed with pyplot in a figure.
So far, I have tried changing the interactive mode, and calling draw() on the figure. However after doing some research, it was to my understanding that draw() is not necessary if you are using plt functions in interactive mode.
I can have it so I repeatedly show a new figure, but I'd like to update the current one so I can keep it in one window.
This is where I initially display the image:
# populating pixelData
self.pixelData = cv.imread(filename)
self.pixelData = cv.cvtColor(self.pixelData, cv.COLOR_BGR2RGB)
plt.ion()
self.image_figure.figimage(self.pixelData, resize=True)
self.image_figure.show()
and then I have a function to call after changing pixelData with one of our filters:
def update_display(self):
self.image_figure.clf()
self.image_figure.figimage(self.pixelData, resize=True)
So, to recap, I want to open up an image, then with my cli tool, modify self.pixelData, then have the displayed image update to reflect the change in self.pixelData
Related
I am creating an interactive matplotlib figure. It is interactive in the sense that when I press a letter 'i' on the keyboard, an image is loaded into the figure. In a second step I would like to remove the image again, while I am still showing the plot. I really don't want to redraw the plot, as it takes too much time.
I am using plt.imshow(img) to display the image. So far I have not come across an equivalent that closes the image. I can only close the complete figure. Does anyone know of such a function?
PLT is tricky. In general, plt.COMMANDS apply to the most recently created object and don't offer much control over the figure, axis, plots, etc. If you label your global plt variables, it makes it more clear.
import matplotlib.pyplot as plt
X = [1,2,3,4]
Y = [1,1,3,3.5]
figure = plt.figure() #Creates the window.
axis = figure.add_subplot(1,1,1) #Creates a graphic inside the window.
axis.grid(True) #Change the axis.
plots = axis.plot(X,Y) #Put a plot in the axis.
figure.show() #Open the window.
Note, that plots is a list, since arrays, X and Y, could have generated many plots. Now, lets delete the plot while the window is open and watch it disappear, then insert the plot back into the axis.
plots[0].remove()
plots = axis.plot(X,Y)
In your case, you are working with axis.imshow() instead of axis.plot().
I've got a loop that's processing images and I want, on every 100th iteration (say) to display the image in a single output window using matplotlib. So I'm trying to write a function which will take a numpy tensor as input and display the corresponding image.
Here's what I have which isn't working:
def display(image):
global im
# If im has been initialized, update it with the current image; otherwise initialize im and update with current image.
try:
im
im.set_array(image)
plt.draw()
except NameError:
im = plt.imshow(image, cmap=plt.get_cmap('gray'), vmin=0, vmax=255)
plt.show(block=False)
plt.draw()
I was trying to pass it through FuncAnimation at first, but that seems designed to have the animation call a function to do the update, rather than having a function call on matplotlib to display the result.
The code above opens a window but it doesn't seem to update. Can anyone point me in the right direction here?
Many thanks,
Justin
Maybe you can use a combination of:
fig.canvas.draw_idle()
and
plt.pause()
The first one will re-draw your figure, while the second one will call the GUI event loop to update the figure.
Also you don't need to call imshow all the times, it's sufficient to call the "set_data" method on your "im" object. Something like that should work:
import matplotlib.pyplot as plt
import numpy
fig,ax = plt.subplots(1,1)
image = numpy.array([[1,1,1], [2,2,2], [3,3,3]])
im = ax.imshow(image)
while True:
image = numpy.multiply(1.1, image)
im.set_data(image)
fig.canvas.draw_idle()
plt.pause(1)
This was adapted from this answer. Hope it helps.
I am using Python 2.7.x with a Jupyter Notebook, matplotlib and %pylab backend with the inline flag
%pylab inline
to print images below active cells. I would like to be able to move my cursor over an image and know it's location and pixel value An example could be:
(x,y,val) = (123,285,230)
but I am not particular about any of the specifics of this example.
The %matplotlib inline backend displays the plot outputs as png images. It may be possible to write some JavaScript for the Jupyter notebook to obtain the color and pixel on mouse over an image in the cell output.
However it may be much easier to just use the %matplotlib notebook backend, which keeps the matplotlib figure alive when plotting it to the output and therefore the usual built-in mouseover functionality is readily available.
Note the picker in the lower right corner of the image, which displays x,y and the value of the current pixel.
To expand on ImportanceOfBeingErnest's answer, you can use mpl_connect to provide a callback on your clicks and ipywidgets to show an output of your callback. If needed, you can break up the code in different cells.
%matplotlib notebook
import matplotlib.pyplot as plt
import numpy as np
import ipywidgets as wdg # Using the ipython notebook widgets
# Create a random image
a = np.random.poisson(size=(12,15))
fig = plt.figure()
plt.imshow(a)
# Create and display textarea widget
txt = wdg.Textarea(
value='',
placeholder='',
description='event:',
disabled=False
)
display(txt)
# Define a callback function that will update the textarea
def onclick(event):
txt.value = str(event) # Dynamically update the text box above
# Create an hard reference to the callback not to be cleared by the garbage collector
ka = fig.canvas.mpl_connect('button_press_event', onclick)
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 implementing an image viewer using matplotlib. The idea is that changes being made to the image (such as filter application) will update automatically.
I create a Figure to show the inital image and have added a button using pyQt to update the data. The data does change, I have checked, but the Figure does not. However, if after I've pressed the filter application button, I move the image using matplotlib's standard tool bar, the image is then updated.
I assume I'm doing something wrong when updating the image, but since the fact of moving it actually forces the update, it then shows the data change. I would like for this to happen when I press the button, though.
Below is some of the code. This is the initial figure initialization, which shows the original image:
self.observableFig = Figure((4.0, 4.0), dpi=100)
self.canvas = FigureCanvas(self.observableFig)
self.canvas.setParent(self.observableWindow)
self.canvas.setFocusPolicy(Qt.StrongFocus)
self.canvas.setFocus()
self.canvas.mpl_connect('button_press_event', self.on_click)
# Showing initial data on Window
self.observableFig.clear()
self.observableAxes = self.observableFig.add_subplot(1, 1, 1)
min, max = self.min, self.max
self.observableAxes.imshow(
self.data,
vmin=min,
vmax=max,
origin='lower'
)
And this is the event for when the button that changes the data is pressed:
self.observableAxes.imshow(self.data/2, origin='lower')
# plt.clf()
# plt.draw()
# plt.show()
I have tried draw(), show(), basically anything I've found on pyplot about this. I have also tried both with and without plt.ion() at the beginning, but it hasn't made a difference in this.
Thanks in advance.
The reason that nothing is updating is that you're trying to use pyplot methods for a figure that's not a part of the pyplot state machine. plt.draw() won't draw this figure, as plt doesn't know the figure exists.
Use fig.canvas.draw() instead.
Regardless, it's better to use fig.canvas.draw() that plt.draw(), as it's clear which figure you're drawing (the former draws one, the latter draws all, but only if they're tracked by pyplot).
Try something along these lines:
import numpy as np
import matplotlib.pyplot as plt
data = np.random.random((10,10))
# To make a standalone example, I'm skipping initializing the
# `Figure` and `FigureCanvas` and using `plt.figure()` instead...
# `plt.draw()` would work for this figure, but the rest is identical.
fig, ax = plt.subplots()
ax.set(title='Click to update the data')
im = ax.imshow(data)
def update(event):
im.set_data(np.random.random((10,10)))
fig.canvas.draw()
fig.canvas.mpl_connect('button_press_event', update)
plt.show()