Thanks to visit codestin.com
Credit goes to github.com

Skip to content

input() blocks any rendering and event handling #10269

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
nbud opened this issue Jan 19, 2018 · 3 comments
Closed

input() blocks any rendering and event handling #10269

nbud opened this issue Jan 19, 2018 · 3 comments
Milestone

Comments

@nbud
Copy link

nbud commented Jan 19, 2018

Bug report

input() blocks any rendering and event handling.

Code for reproduction

Lasso Selector Demo

I ran the code with python, ipython from console and ipython from Spyder 3.2.4 (fails in these three cases).

Actual outcome

The matplotlib window is not rendered and does not respond.

Expected outcome

The matplotlib window should be rendered and allow a lasso selection.

Remark: if the code from input() (included) is removed, the rendering and the lasso selection work as expected.

Matplotlib version

  • Operating system: Windows 7 64 bits
  • Matplotlib version: 2.1.0 and 2.1.1
  • Matplotlib backend: Qt5Agg
  • Python version: Python 3.6.3 :: Anaconda custom (64-bit)
  • Jupyter version (if applicable):
  • Other libraries: IPython 6.1.0

Matplotlib installed with conda, default channel.

@ImportanceOfBeingErnest
Copy link
Member

I can reproduce this behaviour. I never quite understood the drawing to a GUI outside the window's event loop (plt.ion()) and it seems to make much more sense to me to work inside the event loop. In this case one may change the example to the following:

from __future__ import print_function

from six.moves import input

import numpy as np

from matplotlib.widgets import LassoSelector
from matplotlib.path import Path


class SelectFromCollection(object):
    """Select indices from a matplotlib collection using `LassoSelector`.

    Selected indices are saved in the `ind` attribute. This tool fades out the
    points that are not part of the selection (i.e., reduces their alpha
    values). If your collection has alpha < 1, this tool will permanently
    alter the alpha values.

    Note that this tool selects collection objects based on their *origins*
    (i.e., `offsets`).

    Parameters
    ----------
    ax : :class:`~matplotlib.axes.Axes`
        Axes to interact with.

    collection : :class:`matplotlib.collections.Collection` subclass
        Collection you want to select from.

    alpha_other : 0 <= float <= 1
        To highlight a selection, this tool sets all selected points to an
        alpha value of 1 and non-selected points to `alpha_other`.
    """

    def __init__(self, ax, collection, alpha_other=0.3):
        self.canvas = ax.figure.canvas
        self.collection = collection
        self.alpha_other = alpha_other

        self.xys = collection.get_offsets()
        self.Npts = len(self.xys)

        # Ensure that we have separate colors for each object
        self.fc = collection.get_facecolors()
        if len(self.fc) == 0:
            raise ValueError('Collection must have a facecolor')
        elif len(self.fc) == 1:
            self.fc = np.tile(self.fc, (self.Npts, 1))

        self.lasso = LassoSelector(ax, onselect=self.onselect)
        self.ind = []

    def onselect(self, verts):
        path = Path(verts)
        self.ind = np.nonzero(path.contains_points(self.xys))[0]
        self.fc[:, -1] = self.alpha_other
        self.fc[self.ind, -1] = 1
        self.collection.set_facecolors(self.fc)
        self.canvas.draw_idle()

    def disconnect(self):
        self.lasso.disconnect_events()
        self.fc[:, -1] = 1
        self.collection.set_facecolors(self.fc)
        self.canvas.draw_idle()


if __name__ == '__main__':
    import matplotlib.pyplot as plt
    # Fixing random state for reproducibility
    np.random.seed(19680801)

    data = np.random.rand(100, 2)

    subplot_kw = dict(xlim=(0, 1), ylim=(0, 1), autoscale_on=False)
    fig, ax = plt.subplots(subplot_kw=subplot_kw)

    pts = ax.scatter(data[:, 0], data[:, 1], s=80)
    selector = SelectFromCollection(ax, pts)
    
    def accept(event):
        if event.key == "enter":
            print("Selected points:")
            print(selector.xys[selector.ind])
            selector.disconnect()
    cid = fig.canvas.mpl_connect("key_press_event", accept)

    plt.show()

@tacaswell
Copy link
Member

@ImportanceOfBeingErnest See #4779 for a pass at documentation around this, feed back is welcome!

@tacaswell
Copy link
Member

Closing this as #10308 updated the example and because if you are using IPython this is (unfortunately the expected and unavoidable behavior) due to crossed event loops.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants