Commit a6b2d1c3 authored by Loic Huder's avatar Loic Huder
Browse files

Added interactivity part in advanced_matplotlib

parent da3bcb90
......@@ -228,11 +228,144 @@
ax3.plot(X, X**2)
```
%% Cell type:markdown id: tags:
## Interactivity
## Interactivity (https://matplotlib.org/users/event_handling.html)
Know first that other plotting libraries offers interactions more smoothly (`plotly`, `bokeh`, ...). Nevertheless, `matplotlib` gives access to backend-independent methods to add interactivity to plots.
These methods use [`Events`](https://matplotlib.org/api/backend_bases_api.html#matplotlib.backend_bases.Event) to catch user interactions (mouse clicks, key presses, mouse hovers, etc...).
These events must be connected to callback functions using the `mpl_connect` method of `Figure.Canvas`:
```python
fig = plt.figure()
fig.canvas.mpl_connect(self, event_name, callback_func)
```
The signature of `callback_func` is:
```python
def callback_func(event)
```
where event is a `matplotlib.backend_bases.Event`. The following events are recognized
- **'button_press_event'**
- 'button_release_event'
- 'draw_event'
- **'key_press_event'**
- 'key_release_event'
- 'motion_notify_event'
- 'pick_event'
- 'resize_event'
- 'scroll_event'
- 'figure_enter_event',
- 'figure_leave_event',
- 'axes_enter_event',
- 'axes_leave_event'
- **'close_event'**
N.B. : `Figure.Canvas` takes care of the rendering of the figure (independent of the used backend) which is why it is used to handle events.
%% Cell type:markdown id: tags:
### A simple example: changing the color of a line
%% Cell type:code id: tags:
``` python
# Jupyter command to enable interactivity
%matplotlib notebook
f = plt.figure()
ax = f.add_subplot(111)
X = np.arange(0, 10, 0.01)
l, = plt.plot(X, X**2)
def change_color(event):
ax.add.set_color('green')
f.canvas.mpl_connect('button_press_event', change_color)
```
%% Cell type:markdown id: tags:
### Enhanced interactivity: a drawing tool
%% Cell type:code id: tags:
``` python
f2 = plt.figure()
ax2 = f2.add_subplot(111)
ax2.set_aspect('equal')
x_data = []
y_data = []
l, = ax2.plot(x_data, y_data, marker='o')
def add_datapoint(event):
x_data.append(event.xdata)
y_data.append(event.ydata)
l.set_data(x_data, y_data)
f2.canvas.mpl_connect('button_press_event', add_datapoint)
```
%% Cell type:markdown id: tags:
But, here we are referencing `x_data` and `y_data` in `add_datapoint` that are defined outside the function : this breaks encapsulation !
A nicer solution would be to use an object to handle the interactivity. We can also take advantage of this to add more functionality (such as clearing of the figure when the mouse exits) :
%% Cell type:code id: tags:
``` python
class InteractivePlot():
def __init__(self, figure):
self.ax = figure.add_subplot(111)
self.ax.set_aspect('equal')
self.x_data = []
self.y_data = []
self.interactive_line, = self.ax.plot(self.x_data, self.y_data, marker='o')
# Need to keep the callbacks references in memory to have the interactivity
self.button_callback = figure.canvas.mpl_connect('button_press_event', self.add_datapoint)
self.clear_callback = figure.canvas.mpl_connect('figure_leave_event', self.clear)
def add_datapoint(self, event):
if event.button == 1: # Left click
self.x_data.append(event.xdata)
self.y_data.append(event.ydata)
self.update_line()
elif event.button == 3: # Right click
self.x_data = []
self.y_data = []
self.interactive_line, = self.ax.plot(self.x_data, self.y_data, marker='o')
def clear(self, event):
self.ax.clear()
self.x_data = []
self.y_data = []
self.interactive_line, = self.ax.plot(self.x_data, self.y_data, marker='o')
def update_line(self):
self.interactive_line.set_data(self.x_data, self.y_data)
f = plt.figure()
ip = InteractivePlot(f)
```
%% Cell type:markdown id: tags:
More examples could be shown but it always revolves around the same process: connecting an `Event` to a callback function.
Note that the connection can be severed using `mpl_disconnect` that takes the callback id in arg (in the previous case `self.button_callback` or `self.clear_callback`.
Some usages of interactivity:
- Print the value of a point on click
- Trigger a plot in the third dimension of a 3D plot displayed in 2D
- Save a figure on closing
- Ideas ?
%% Cell type:markdown id: tags:
## Animations
......@@ -251,10 +384,11 @@
The animation consists in making repeated calls to the `update` function that adds at each frame a datapoint to the plot.
%% Cell type:code id: tags:
``` python
%matplotlib inline
from matplotlib import animation
fig, ax = plt.subplots()
xdata, ydata = [], []
ln, = plt.plot([], [], 'ro')
......@@ -275,11 +409,11 @@
plt.show()
```
%% Cell type:markdown id: tags:
The previous code executed in a regular Python script should display the animation without problem. In a Jupyter Notebook, it is necessary to use IPython to display it in HTML.
The previous code executed in a regular Python script should display the animation without problem. In a Jupyter Notebook, if we use `%matplotlib inline`, we can use IPython to display it in HTML.
%% Cell type:code id: tags:
``` python
from IPython.display import HTML
......@@ -296,11 +430,11 @@
Ex: Naming blue for <div style='text-align:center; font-size:36px'><span style='color:blue'>RED</span> vs. <span style='color:blue'>BIRD</span></div>
_Funfact: As this test relies on the significance of the words, people that are more used to English should find the test more difficult !_
In this part, we show how `matplotlib` animations can generate a Stroop test that shows random color words in random colors at random positions. The person passing the test should then name the color in which the word is written.
In this part, we show how `matplotlib` animations can generate a Stroop test that shows random color words in random colors at random positions.
#### With `FuncAnimation`
We will generate a single object `word` whose position, color and text will be updated by the repeatedly called function.
%% Cell type:code id: tags:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment