Fixed database typo and removed unnecessary class identifier.
This commit is contained in:
parent
00ad49a143
commit
45fb349a7d
5098 changed files with 952558 additions and 85 deletions
356
venv/Lib/site-packages/matplotlib/blocking_input.py
Normal file
356
venv/Lib/site-packages/matplotlib/blocking_input.py
Normal file
|
@ -0,0 +1,356 @@
|
|||
"""
|
||||
Classes used for blocking interaction with figure windows:
|
||||
|
||||
`BlockingInput`
|
||||
Creates a callable object to retrieve events in a blocking way for
|
||||
interactive sessions. Base class of the other classes listed here.
|
||||
|
||||
`BlockingKeyMouseInput`
|
||||
Creates a callable object to retrieve key or mouse clicks in a blocking
|
||||
way for interactive sessions. Used by `~.Figure.waitforbuttonpress`.
|
||||
|
||||
`BlockingMouseInput`
|
||||
Creates a callable object to retrieve mouse clicks in a blocking way for
|
||||
interactive sessions. Used by `~.Figure.ginput`.
|
||||
|
||||
`BlockingContourLabeler`
|
||||
Creates a callable object to retrieve mouse clicks in a blocking way that
|
||||
will then be used to place labels on a `.ContourSet`. Used by
|
||||
`~.Axes.clabel`.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from numbers import Integral
|
||||
|
||||
from matplotlib import cbook
|
||||
from matplotlib.backend_bases import MouseButton
|
||||
import matplotlib.lines as mlines
|
||||
|
||||
_log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BlockingInput:
|
||||
"""Callable for retrieving events in a blocking way."""
|
||||
|
||||
def __init__(self, fig, eventslist=()):
|
||||
self.fig = fig
|
||||
self.eventslist = eventslist
|
||||
|
||||
def on_event(self, event):
|
||||
"""
|
||||
Event handler; will be passed to the current figure to retrieve events.
|
||||
"""
|
||||
# Add a new event to list - using a separate function is overkill for
|
||||
# the base class, but this is consistent with subclasses.
|
||||
self.add_event(event)
|
||||
_log.info("Event %i", len(self.events))
|
||||
|
||||
# This will extract info from events.
|
||||
self.post_event()
|
||||
|
||||
# Check if we have enough events already.
|
||||
if len(self.events) >= self.n > 0:
|
||||
self.fig.canvas.stop_event_loop()
|
||||
|
||||
def post_event(self):
|
||||
"""For baseclass, do nothing but collect events."""
|
||||
|
||||
def cleanup(self):
|
||||
"""Disconnect all callbacks."""
|
||||
for cb in self.callbacks:
|
||||
self.fig.canvas.mpl_disconnect(cb)
|
||||
self.callbacks = []
|
||||
|
||||
def add_event(self, event):
|
||||
"""For base class, this just appends an event to events."""
|
||||
self.events.append(event)
|
||||
|
||||
def pop_event(self, index=-1):
|
||||
"""
|
||||
Remove an event from the event list -- by default, the last.
|
||||
|
||||
Note that this does not check that there are events, much like the
|
||||
normal pop method. If no events exist, this will throw an exception.
|
||||
"""
|
||||
self.events.pop(index)
|
||||
|
||||
pop = pop_event
|
||||
|
||||
def __call__(self, n=1, timeout=30):
|
||||
"""Blocking call to retrieve *n* events."""
|
||||
cbook._check_isinstance(Integral, n=n)
|
||||
self.n = n
|
||||
self.events = []
|
||||
|
||||
if hasattr(self.fig.canvas, "manager"):
|
||||
# Ensure that the figure is shown, if we are managing it.
|
||||
self.fig.show()
|
||||
# Connect the events to the on_event function call.
|
||||
self.callbacks = [self.fig.canvas.mpl_connect(name, self.on_event)
|
||||
for name in self.eventslist]
|
||||
try:
|
||||
# Start event loop.
|
||||
self.fig.canvas.start_event_loop(timeout=timeout)
|
||||
finally: # Run even on exception like ctrl-c.
|
||||
# Disconnect the callbacks.
|
||||
self.cleanup()
|
||||
# Return the events in this case.
|
||||
return self.events
|
||||
|
||||
|
||||
class BlockingMouseInput(BlockingInput):
|
||||
"""
|
||||
Callable for retrieving mouse clicks in a blocking way.
|
||||
|
||||
This class will also retrieve keypresses and map them to mouse clicks:
|
||||
delete and backspace are a right click, enter is like a middle click,
|
||||
and all others are like a left click.
|
||||
"""
|
||||
|
||||
button_add = MouseButton.LEFT
|
||||
button_pop = MouseButton.RIGHT
|
||||
button_stop = MouseButton.MIDDLE
|
||||
|
||||
def __init__(self, fig,
|
||||
mouse_add=MouseButton.LEFT,
|
||||
mouse_pop=MouseButton.RIGHT,
|
||||
mouse_stop=MouseButton.MIDDLE):
|
||||
BlockingInput.__init__(self, fig=fig,
|
||||
eventslist=('button_press_event',
|
||||
'key_press_event'))
|
||||
self.button_add = mouse_add
|
||||
self.button_pop = mouse_pop
|
||||
self.button_stop = mouse_stop
|
||||
|
||||
def post_event(self):
|
||||
"""Process an event."""
|
||||
if len(self.events) == 0:
|
||||
_log.warning("No events yet")
|
||||
elif self.events[-1].name == 'key_press_event':
|
||||
self.key_event()
|
||||
else:
|
||||
self.mouse_event()
|
||||
|
||||
def mouse_event(self):
|
||||
"""Process a mouse click event."""
|
||||
event = self.events[-1]
|
||||
button = event.button
|
||||
if button == self.button_pop:
|
||||
self.mouse_event_pop(event)
|
||||
elif button == self.button_stop:
|
||||
self.mouse_event_stop(event)
|
||||
elif button == self.button_add:
|
||||
self.mouse_event_add(event)
|
||||
|
||||
def key_event(self):
|
||||
"""
|
||||
Process a key press event, mapping keys to appropriate mouse clicks.
|
||||
"""
|
||||
event = self.events[-1]
|
||||
if event.key is None:
|
||||
# At least in OSX gtk backend some keys return None.
|
||||
return
|
||||
key = event.key.lower()
|
||||
if key in ['backspace', 'delete']:
|
||||
self.mouse_event_pop(event)
|
||||
elif key in ['escape', 'enter']:
|
||||
self.mouse_event_stop(event)
|
||||
else:
|
||||
self.mouse_event_add(event)
|
||||
|
||||
def mouse_event_add(self, event):
|
||||
"""
|
||||
Process an button-1 event (add a click if inside axes).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
event : `~.backend_bases.MouseEvent`
|
||||
"""
|
||||
if event.inaxes:
|
||||
self.add_click(event)
|
||||
else: # If not a valid click, remove from event list.
|
||||
BlockingInput.pop(self)
|
||||
|
||||
def mouse_event_stop(self, event):
|
||||
"""
|
||||
Process an button-2 event (end blocking input).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
event : `~.backend_bases.MouseEvent`
|
||||
"""
|
||||
# Remove last event just for cleanliness.
|
||||
BlockingInput.pop(self)
|
||||
# This will exit even if not in infinite mode. This is consistent with
|
||||
# MATLAB and sometimes quite useful, but will require the user to test
|
||||
# how many points were actually returned before using data.
|
||||
self.fig.canvas.stop_event_loop()
|
||||
|
||||
def mouse_event_pop(self, event):
|
||||
"""
|
||||
Process an button-3 event (remove the last click).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
event : `~.backend_bases.MouseEvent`
|
||||
"""
|
||||
# Remove this last event.
|
||||
BlockingInput.pop(self)
|
||||
# Now remove any existing clicks if possible.
|
||||
if self.events:
|
||||
self.pop(event)
|
||||
|
||||
def add_click(self, event):
|
||||
"""
|
||||
Add the coordinates of an event to the list of clicks.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
event : `~.backend_bases.MouseEvent`
|
||||
"""
|
||||
self.clicks.append((event.xdata, event.ydata))
|
||||
_log.info("input %i: %f, %f",
|
||||
len(self.clicks), event.xdata, event.ydata)
|
||||
# If desired, plot up click.
|
||||
if self.show_clicks:
|
||||
line = mlines.Line2D([event.xdata], [event.ydata],
|
||||
marker='+', color='r')
|
||||
event.inaxes.add_line(line)
|
||||
self.marks.append(line)
|
||||
self.fig.canvas.draw()
|
||||
|
||||
def pop_click(self, event, index=-1):
|
||||
"""
|
||||
Remove a click (by default, the last) from the list of clicks.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
event : `~.backend_bases.MouseEvent`
|
||||
"""
|
||||
self.clicks.pop(index)
|
||||
if self.show_clicks:
|
||||
self.marks.pop(index).remove()
|
||||
self.fig.canvas.draw()
|
||||
|
||||
def pop(self, event, index=-1):
|
||||
"""
|
||||
Remove a click and the associated event from the list of clicks.
|
||||
|
||||
Defaults to the last click.
|
||||
"""
|
||||
self.pop_click(event, index)
|
||||
BlockingInput.pop(self, index)
|
||||
|
||||
def cleanup(self, event=None):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
event : `~.backend_bases.MouseEvent`, optional
|
||||
Not used
|
||||
"""
|
||||
# Clean the figure.
|
||||
if self.show_clicks:
|
||||
for mark in self.marks:
|
||||
mark.remove()
|
||||
self.marks = []
|
||||
self.fig.canvas.draw()
|
||||
# Call base class to remove callbacks.
|
||||
BlockingInput.cleanup(self)
|
||||
|
||||
def __call__(self, n=1, timeout=30, show_clicks=True):
|
||||
"""
|
||||
Blocking call to retrieve *n* coordinate pairs through mouse clicks.
|
||||
"""
|
||||
self.show_clicks = show_clicks
|
||||
self.clicks = []
|
||||
self.marks = []
|
||||
BlockingInput.__call__(self, n=n, timeout=timeout)
|
||||
return self.clicks
|
||||
|
||||
|
||||
class BlockingContourLabeler(BlockingMouseInput):
|
||||
"""
|
||||
Callable for retrieving mouse clicks and key presses in a blocking way.
|
||||
|
||||
Used to place contour labels.
|
||||
"""
|
||||
|
||||
def __init__(self, cs):
|
||||
self.cs = cs
|
||||
BlockingMouseInput.__init__(self, fig=cs.ax.figure)
|
||||
|
||||
def add_click(self, event):
|
||||
self.button1(event)
|
||||
|
||||
def pop_click(self, event, index=-1):
|
||||
self.button3(event)
|
||||
|
||||
def button1(self, event):
|
||||
"""
|
||||
Process an button-1 event (add a label to a contour).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
event : `~.backend_bases.MouseEvent`
|
||||
"""
|
||||
# Shorthand
|
||||
if event.inaxes == self.cs.ax:
|
||||
self.cs.add_label_near(event.x, event.y, self.inline,
|
||||
inline_spacing=self.inline_spacing,
|
||||
transform=False)
|
||||
self.fig.canvas.draw()
|
||||
else: # Remove event if not valid
|
||||
BlockingInput.pop(self)
|
||||
|
||||
def button3(self, event):
|
||||
"""
|
||||
Process an button-3 event (remove a label if not in inline mode).
|
||||
|
||||
Unfortunately, if one is doing inline labels, then there is currently
|
||||
no way to fix the broken contour - once humpty-dumpty is broken, he
|
||||
can't be put back together. In inline mode, this does nothing.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
event : `~.backend_bases.MouseEvent`
|
||||
"""
|
||||
if self.inline:
|
||||
pass
|
||||
else:
|
||||
self.cs.pop_label()
|
||||
self.cs.ax.figure.canvas.draw()
|
||||
|
||||
def __call__(self, inline, inline_spacing=5, n=-1, timeout=-1):
|
||||
self.inline = inline
|
||||
self.inline_spacing = inline_spacing
|
||||
BlockingMouseInput.__call__(self, n=n, timeout=timeout,
|
||||
show_clicks=False)
|
||||
|
||||
|
||||
class BlockingKeyMouseInput(BlockingInput):
|
||||
"""
|
||||
Callable for retrieving mouse clicks and key presses in a blocking way.
|
||||
"""
|
||||
|
||||
def __init__(self, fig):
|
||||
BlockingInput.__init__(self, fig=fig, eventslist=(
|
||||
'button_press_event', 'key_press_event'))
|
||||
|
||||
def post_event(self):
|
||||
"""Determine if it is a key event."""
|
||||
if self.events:
|
||||
self.keyormouse = self.events[-1].name == 'key_press_event'
|
||||
else:
|
||||
_log.warning("No events yet.")
|
||||
|
||||
def __call__(self, timeout=30):
|
||||
"""
|
||||
Blocking call to retrieve a single mouse click or key press.
|
||||
|
||||
Returns ``True`` if key press, ``False`` if mouse click, or ``None`` if
|
||||
timed out.
|
||||
"""
|
||||
self.keyormouse = None
|
||||
BlockingInput.__call__(self, n=1, timeout=timeout)
|
||||
|
||||
return self.keyormouse
|
Loading…
Add table
Add a link
Reference in a new issue