Widget event issue #5812

Hello

I have an issue on widget events. I have created a figure which contains
several subplots. When click on one of the subplots, it shows another
figure. This new figure contains button and rectangle selector widgets.
Until this it works fine. Problem is nothing happens if I click on the
buttons or draw rectangle on this new figure. It works well (i mean button
onclick, line_select_callback events raise ), if I just create figure not
after click the subplots. I do not know what I am doing wrong. Please help
me.

By the way, I am using:
matplotlib.*version* : '1.4.3'
matplotlib.get_backend() : Qt4Agg
python: 2.7.10 | Anaconda 2.3.0 (64-bit)

Here is the some part of code that I having problem:

import sys

import cv2

from matplotlib.widgets import RectangleSelector

import matplotlib.pyplot as plt

from matplotlib.widgets import Button

def main_window():

    def open_figure(event):

        ax = event.inaxes

        if ax is None:

            # Occurs when a region not in an axis is clicked...

            return

        for i in xrange(len(event.canvas.figure.axes)):

            if event.canvas.figure.axes[i] is ax:

                plt.ion()

                # Show clicked image on new figure

                show_new_figure(im)

        fig = plt.figure(1)

        # some code which locates subplots

        # show images on subplots

        show_image(im)

        fig.canvas.mpl_connect('button_press_event', open_figure)

        plt.show()

def show_image(im):

    im = im[:, :, (2, 1, 0)]

    plt.cla()

    plt.imshow(im)

    plt.axis('off')

    plt.draw()

    # plt.show()

def show_new_figure(im):

    class Btn:

        def save(self, event):

            plt.close()

        def close(self, event):

            plt.close()

        def exit(self, event):

            sys.exit()

    callback = Btn()

    im = im[:, :, (2, 1, 0)]

    fig2, ax = plt.subplots(figsize=(10, 10))

    plt.cla()

    plt.imshow(im)

    axSave = plt.axes([0.5, 0.01, 0.1, 0.075])

    axClose = plt.axes([0.39, 0.01, 0.1, 0.075])

    axExit = plt.axes([0.6, 0.01, 0.1, 0.075])

    btnSave = Button(axSave, 'Save')

    btnSave.on_clicked(callback.save)

    btnClose = Button(axClose, 'Close')

    btnClose.on_clicked(callback.close)

    btnExit = Button(axExit, 'Exit')

    btnExit.on_clicked(callback.exit)

    # draw rectangle

    def line_select_callback(eclick, erelease):

        'eclick and erelease are the press and release events'

        x1, y1 = eclick.xdata, eclick.ydata

        x2, y2 = erelease.xdata, erelease.ydata

        print ("X, Y points: (%3.2f, %3.2f) --> (%3.2f, %3.2f)" % (x1, y1,
x2, y2))

    rs = RectangleSelector(ax, line_select_callback,

                           drawtype='box', useblit=True,

                           button=[1, 3],

                           minspanx=5, minspany=5,

                           rectprops=dict(facecolor='blue',
edgecolor='blue',

                                            alpha=1, fill=False),

                           spancoords='pixels')

    rs.set_active(True)

    plt.axis('off')

    plt.show()

Thank you for consideration.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/matplotlib-users/attachments/20160108/76d6409b/attachment-0001.html>

There is something a bit sutble going on here, see the following code:

import matplotlib.pyplot as plt
from six.moves import range
import sys

from matplotlib.widgets import RectangleSelector
from matplotlib.widgets import Button

def main_window(im):
    ref_holder = dict()

    def open_figure(event):
        ax = event.inaxes
        if ax is None:
            # Occurs when a region not in an axis is clicked...
            return
        for i in range(len(event.canvas.figure.axes)):
            if event.canvas.figure.axes[i] is ax:
                ret = show_new_figure(im)
                ref_holder['last interactive'] = ret

    fig, ax = plt.subplots()

    # some code which locates subplots
    # show images on subplots
    show_image(ax, im)

    fig.canvas.mpl_connect('button_press_event', open_figure)
    plt.show()

    return fig, ax

def show_image(ax, im):
    ax.cla()
    ax.imshow(im, cmap='gray', interpolation='nearest')

def show_new_figure(im):
    fig, ax = plt.subplots(figsize=(10, 10))

    class Btn(object):
        def save(self, event):
            fig.canvas.manager.toolbar.save_figure()

        def close(self, event):
            plt.close(fig)

        def exit(self, event):
            sys.exit()

    callback = Btn()

    ax.imshow(im, cmap='Reds', interpolation='nearest')

    axSave = plt.axes([0.5, 0.01, 0.1, 0.075])
    axClose = plt.axes([0.39, 0.01, 0.1, 0.075])
    axExit = plt.axes([0.6, 0.01, 0.1, 0.075])

    btnSave = Button(axSave, 'Save')
    btnSave.on_clicked(callback.save)
    btnClose = Button(axClose, 'Close')
    btnClose.on_clicked(callback.close)
    btnExit = Button(axExit, 'Exit')
    btnExit.on_clicked(callback.exit)

    # draw rectangle
    def line_select_callback(eclick, erelease):
        'eclick and erelease are the press and release events'
        x1, y1 = eclick.xdata, eclick.ydata
        x2, y2 = erelease.xdata, erelease.ydata
        print("X, Y points: (%3.2f, %3.2f) --> (%3.2f, %3.2f)" %
              (x1, y1, x2, y2))

    rs = RectangleSelector(ax, line_select_callback,
                           drawtype='box', useblit=True,
                           button=[1, 3],
                           minspanx=5, minspany=5,
                           rectprops=dict(facecolor='blue',
edgecolor='blue',
                                          alpha=1, fill=False),
                           spancoords='pixels')
    rs.set_active(True)

    return rs, btnSave, btnClose, btnExit

The critical bit is that the `show_new_figure` function is returning the
`widget` objects and `open_figure` is stashing them in a local dictionary.
What is happening is that without holding on to a reference to the widget
objects they get garbage collected. By design, the callback registries
only hold on to a weak-ref (that is a reference that will not prevent
garbage collection if it is the last reference left), so if you do not keep
a reference to the widgets, the get garbage collections and hence do not
exist to get the click events. This is documented in the widget class
docstring (ex
http://matplotlib.org/api/widgets_api.html#matplotlib.widgets.Button)

Tom

···

On Thu, Jan 7, 2016 at 9:52 PM Enkhbayar Erdenee <enkhee.data at gmail.com> wrote:

Hello

I have an issue on widget events. I have created a figure which contains
several subplots. When click on one of the subplots, it shows another
figure. This new figure contains button and rectangle selector widgets.
Until this it works fine. Problem is nothing happens if I click on the
buttons or draw rectangle on this new figure. It works well (i mean button
onclick, line_select_callback events raise ), if I just create figure not
after click the subplots. I do not know what I am doing wrong. Please help
me.

By the way, I am using:
matplotlib.*version* : '1.4.3'
matplotlib.get_backend() : Qt4Agg
python: 2.7.10 | Anaconda 2.3.0 (64-bit)

Here is the some part of code that I having problem:

import sys

import cv2

from matplotlib.widgets import RectangleSelector

import matplotlib.pyplot as plt

from matplotlib.widgets import Button

def main_window():

    def open_figure(event):

        ax = event.inaxes

        if ax is None:

            # Occurs when a region not in an axis is clicked...

            return

        for i in xrange(len(event.canvas.figure.axes)):

            if event.canvas.figure.axes[i] is ax:

                plt.ion()

                # Show clicked image on new figure

                show_new_figure(im)

        fig = plt.figure(1)

        # some code which locates subplots

        # show images on subplots

        show_image(im)

        fig.canvas.mpl_connect('button_press_event', open_figure)

        plt.show()

def show_image(im):

    im = im[:, :, (2, 1, 0)]

    plt.cla()

    plt.imshow(im)

    plt.axis('off')

    plt.draw()

    # plt.show()

def show_new_figure(im):

    class Btn:

        def save(self, event):

            plt.close()

        def close(self, event):

            plt.close()

        def exit(self, event):

            sys.exit()

    callback = Btn()

    im = im[:, :, (2, 1, 0)]

    fig2, ax = plt.subplots(figsize=(10, 10))

    plt.cla()

    plt.imshow(im)

    axSave = plt.axes([0.5, 0.01, 0.1, 0.075])

    axClose = plt.axes([0.39, 0.01, 0.1, 0.075])

    axExit = plt.axes([0.6, 0.01, 0.1, 0.075])

    btnSave = Button(axSave, 'Save')

    btnSave.on_clicked(callback.save)

    btnClose = Button(axClose, 'Close')

    btnClose.on_clicked(callback.close)

    btnExit = Button(axExit, 'Exit')

    btnExit.on_clicked(callback.exit)

    # draw rectangle

    def line_select_callback(eclick, erelease):

        'eclick and erelease are the press and release events'

        x1, y1 = eclick.xdata, eclick.ydata

        x2, y2 = erelease.xdata, erelease.ydata

        print ("X, Y points: (%3.2f, %3.2f) --> (%3.2f, %3.2f)" % (x1, y1,
x2, y2))

    rs = RectangleSelector(ax, line_select_callback,

                           drawtype='box', useblit=True,

                           button=[1, 3],

                           minspanx=5, minspany=5,

                           rectprops=dict(facecolor='blue',
edgecolor='blue',

                                            alpha=1, fill=False),

                           spancoords='pixels')

    rs.set_active(True)

    plt.axis('off')

    plt.show()

Thank you for consideration.
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users at python.org
Matplotlib-users Info Page

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/matplotlib-users/attachments/20160108/6e7303a0/attachment-0001.html&gt;

Thank you for taking time. I have changed the code according to your advice
and it works well. Now I have a clear understanding how to use pyplot and
widgets of matplotlib. Thank you again, your advice helped me a lot :slight_smile:

···

On Fri, Jan 8, 2016 at 12:29 PM, Thomas Caswell <tcaswell at gmail.com> wrote:

There is something a bit sutble going on here, see the following code:

import matplotlib.pyplot as plt
from six.moves import range
import sys

from matplotlib.widgets import RectangleSelector
from matplotlib.widgets import Button

def main_window(im):
    ref_holder = dict()

    def open_figure(event):
        ax = event.inaxes
        if ax is None:
            # Occurs when a region not in an axis is clicked...
            return
        for i in range(len(event.canvas.figure.axes)):
            if event.canvas.figure.axes[i] is ax:
                ret = show_new_figure(im)
                ref_holder['last interactive'] = ret

    fig, ax = plt.subplots()

    # some code which locates subplots
    # show images on subplots
    show_image(ax, im)

    fig.canvas.mpl_connect('button_press_event', open_figure)
    plt.show()

    return fig, ax

def show_image(ax, im):
    ax.cla()
    ax.imshow(im, cmap='gray', interpolation='nearest')

def show_new_figure(im):
    fig, ax = plt.subplots(figsize=(10, 10))

    class Btn(object):
        def save(self, event):
            fig.canvas.manager.toolbar.save_figure()

        def close(self, event):
            plt.close(fig)

        def exit(self, event):
            sys.exit()

    callback = Btn()

    ax.imshow(im, cmap='Reds', interpolation='nearest')

    axSave = plt.axes([0.5, 0.01, 0.1, 0.075])
    axClose = plt.axes([0.39, 0.01, 0.1, 0.075])
    axExit = plt.axes([0.6, 0.01, 0.1, 0.075])

    btnSave = Button(axSave, 'Save')
    btnSave.on_clicked(callback.save)
    btnClose = Button(axClose, 'Close')
    btnClose.on_clicked(callback.close)
    btnExit = Button(axExit, 'Exit')
    btnExit.on_clicked(callback.exit)

    # draw rectangle
    def line_select_callback(eclick, erelease):
        'eclick and erelease are the press and release events'
        x1, y1 = eclick.xdata, eclick.ydata
        x2, y2 = erelease.xdata, erelease.ydata
        print("X, Y points: (%3.2f, %3.2f) --> (%3.2f, %3.2f)" %
              (x1, y1, x2, y2))

    rs = RectangleSelector(ax, line_select_callback,
                           drawtype='box', useblit=True,
                           button=[1, 3],
                           minspanx=5, minspany=5,
                           rectprops=dict(facecolor='blue',
edgecolor='blue',
                                          alpha=1, fill=False),
                           spancoords='pixels')
    rs.set_active(True)

    return rs, btnSave, btnClose, btnExit

The critical bit is that the `show_new_figure` function is returning the
`widget` objects and `open_figure` is stashing them in a local dictionary.
What is happening is that without holding on to a reference to the widget
objects they get garbage collected. By design, the callback registries
only hold on to a weak-ref (that is a reference that will not prevent
garbage collection if it is the last reference left), so if you do not keep
a reference to the widgets, the get garbage collections and hence do not
exist to get the click events. This is documented in the widget class
docstring (ex
http://matplotlib.org/api/widgets_api.html#matplotlib.widgets.Button)

Tom

On Thu, Jan 7, 2016 at 9:52 PM Enkhbayar Erdenee <enkhee.data at gmail.com> > wrote:

Hello

I have an issue on widget events. I have created a figure which contains
several subplots. When click on one of the subplots, it shows another
figure. This new figure contains button and rectangle selector widgets.
Until this it works fine. Problem is nothing happens if I click on the
buttons or draw rectangle on this new figure. It works well (i mean button
onclick, line_select_callback events raise ), if I just create figure not
after click the subplots. I do not know what I am doing wrong. Please help
me.

By the way, I am using:
matplotlib.*version* : '1.4.3'
matplotlib.get_backend() : Qt4Agg
python: 2.7.10 | Anaconda 2.3.0 (64-bit)

Here is the some part of code that I having problem:

import sys

import cv2

from matplotlib.widgets import RectangleSelector

import matplotlib.pyplot as plt

from matplotlib.widgets import Button

def main_window():

    def open_figure(event):

        ax = event.inaxes

        if ax is None:

            # Occurs when a region not in an axis is clicked...

            return

        for i in xrange(len(event.canvas.figure.axes)):

            if event.canvas.figure.axes[i] is ax:

                plt.ion()

                # Show clicked image on new figure

                show_new_figure(im)

        fig = plt.figure(1)

        # some code which locates subplots

        # show images on subplots

        show_image(im)

        fig.canvas.mpl_connect('button_press_event', open_figure)

        plt.show()

def show_image(im):

    im = im[:, :, (2, 1, 0)]

    plt.cla()

    plt.imshow(im)

    plt.axis('off')

    plt.draw()

    # plt.show()

def show_new_figure(im):

    class Btn:

        def save(self, event):

            plt.close()

        def close(self, event):

            plt.close()

        def exit(self, event):

            sys.exit()

    callback = Btn()

    im = im[:, :, (2, 1, 0)]

    fig2, ax = plt.subplots(figsize=(10, 10))

    plt.cla()

    plt.imshow(im)

    axSave = plt.axes([0.5, 0.01, 0.1, 0.075])

    axClose = plt.axes([0.39, 0.01, 0.1, 0.075])

    axExit = plt.axes([0.6, 0.01, 0.1, 0.075])

    btnSave = Button(axSave, 'Save')

    btnSave.on_clicked(callback.save)

    btnClose = Button(axClose, 'Close')

    btnClose.on_clicked(callback.close)

    btnExit = Button(axExit, 'Exit')

    btnExit.on_clicked(callback.exit)

    # draw rectangle

    def line_select_callback(eclick, erelease):

        'eclick and erelease are the press and release events'

        x1, y1 = eclick.xdata, eclick.ydata

        x2, y2 = erelease.xdata, erelease.ydata

        print ("X, Y points: (%3.2f, %3.2f) --> (%3.2f, %3.2f)" % (x1,
y1, x2, y2))

    rs = RectangleSelector(ax, line_select_callback,

                           drawtype='box', useblit=True,

                           button=[1, 3],

                           minspanx=5, minspany=5,

                           rectprops=dict(facecolor='blue',
edgecolor='blue',

                                            alpha=1, fill=False),

                           spancoords='pixels')

    rs.set_active(True)

    plt.axis('off')

    plt.show()

Thank you for consideration.
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users at python.org
Matplotlib-users Info Page

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/matplotlib-users/attachments/20160108/a5b90bc4/attachment-0001.html&gt;