6

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.

NerdOnTour
  • 634
  • 4
  • 15

1 Answers1

13

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()
Joe Kington
  • 275,208
  • 71
  • 604
  • 463
  • Thank you for your answer. I would like to know what you mean with "the latter draws all, but only if they're tracked by `pyplot`" though... is there a way I can actually add figures to be "tracked" by `pyplot`? I imagine this could be useful when wanting to refresh many figures – Francisca Concha-Ramírez Jun 17 '15 at 15:16
  • 1
    @Fran - By "tracked by pyplot", I basically mean "created using `plt.figure()` or `plt.subplots()`. It sounds like you're embedding matplotlib in a gui framework of some sort? If so, you _don't_ want things tracked by pyplot in that sense. Otherwise, they'll have their own gui windows. If you're not writing a separate gui application, though, then it's best to create figures using pyplot for exactly the reason you just mentioned. – Joe Kington Jun 17 '15 at 15:22