mirror of
https://github.com/Estom/notes.git
synced 2026-04-10 06:18:46 +08:00
matplotlib & pandas
This commit is contained in:
24
Python/matplotlab/gallery/event_handling/close_event.md
Normal file
24
Python/matplotlab/gallery/event_handling/close_event.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# 关闭事件
|
||||
|
||||
显示图形关闭时发生的连接事件的示例。
|
||||
|
||||

|
||||
|
||||
```python
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
|
||||
def handle_close(evt):
|
||||
print('Closed Figure!')
|
||||
|
||||
fig = plt.figure()
|
||||
fig.canvas.mpl_connect('close_event', handle_close)
|
||||
|
||||
plt.text(0.35, 0.5, 'Close Me!', dict(size=30))
|
||||
plt.show()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: close_event.py](https://matplotlib.org/_downloads/close_event.py)
|
||||
- [下载Jupyter notebook: close_event.ipynb](https://matplotlib.org/_downloads/close_event.ipynb)
|
||||
48
Python/matplotlab/gallery/event_handling/coords_demo.md
Normal file
48
Python/matplotlab/gallery/event_handling/coords_demo.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# Coords 演示
|
||||
|
||||
如何通过连接到移动和单击事件来与绘图画布交互的示例
|
||||
|
||||

|
||||
|
||||
```python
|
||||
import sys
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
t = np.arange(0.0, 1.0, 0.01)
|
||||
s = np.sin(2 * np.pi * t)
|
||||
fig, ax = plt.subplots()
|
||||
ax.plot(t, s)
|
||||
|
||||
|
||||
def on_move(event):
|
||||
# get the x and y pixel coords
|
||||
x, y = event.x, event.y
|
||||
|
||||
if event.inaxes:
|
||||
ax = event.inaxes # the axes instance
|
||||
print('data coords %f %f' % (event.xdata, event.ydata))
|
||||
|
||||
|
||||
def on_click(event):
|
||||
# get the x and y coords, flip y from top to bottom
|
||||
x, y = event.x, event.y
|
||||
if event.button == 1:
|
||||
if event.inaxes is not None:
|
||||
print('data coords %f %f' % (event.xdata, event.ydata))
|
||||
|
||||
|
||||
binding_id = plt.connect('motion_notify_event', on_move)
|
||||
plt.connect('button_press_event', on_click)
|
||||
|
||||
if "test_disconnect" in sys.argv:
|
||||
print("disconnecting console coordinate printout...")
|
||||
plt.disconnect(binding_id)
|
||||
|
||||
plt.show()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: coords_demo.py](https://matplotlib.org/_downloads/coords_demo.py)
|
||||
- [下载Jupyter notebook: coords_demo.ipynb](https://matplotlib.org/_downloads/coords_demo.ipynb)
|
||||
105
Python/matplotlab/gallery/event_handling/data_browser.md
Normal file
105
Python/matplotlab/gallery/event_handling/data_browser.md
Normal file
@@ -0,0 +1,105 @@
|
||||
# 数据浏览器
|
||||
|
||||
在多个画布之间连接数据。
|
||||
|
||||
此示例介绍了如何与多个画布交互数据。这样,您可以选择并突出显示一个轴上的点,并在另一个轴上生成该点的数据。
|
||||
|
||||

|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
|
||||
|
||||
class PointBrowser(object):
|
||||
"""
|
||||
Click on a point to select and highlight it -- the data that
|
||||
generated the point will be shown in the lower axes. Use the 'n'
|
||||
and 'p' keys to browse through the next and previous points
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.lastind = 0
|
||||
|
||||
self.text = ax.text(0.05, 0.95, 'selected: none',
|
||||
transform=ax.transAxes, va='top')
|
||||
self.selected, = ax.plot([xs[0]], [ys[0]], 'o', ms=12, alpha=0.4,
|
||||
color='yellow', visible=False)
|
||||
|
||||
def onpress(self, event):
|
||||
if self.lastind is None:
|
||||
return
|
||||
if event.key not in ('n', 'p'):
|
||||
return
|
||||
if event.key == 'n':
|
||||
inc = 1
|
||||
else:
|
||||
inc = -1
|
||||
|
||||
self.lastind += inc
|
||||
self.lastind = np.clip(self.lastind, 0, len(xs) - 1)
|
||||
self.update()
|
||||
|
||||
def onpick(self, event):
|
||||
|
||||
if event.artist != line:
|
||||
return True
|
||||
|
||||
N = len(event.ind)
|
||||
if not N:
|
||||
return True
|
||||
|
||||
# the click locations
|
||||
x = event.mouseevent.xdata
|
||||
y = event.mouseevent.ydata
|
||||
|
||||
distances = np.hypot(x - xs[event.ind], y - ys[event.ind])
|
||||
indmin = distances.argmin()
|
||||
dataind = event.ind[indmin]
|
||||
|
||||
self.lastind = dataind
|
||||
self.update()
|
||||
|
||||
def update(self):
|
||||
if self.lastind is None:
|
||||
return
|
||||
|
||||
dataind = self.lastind
|
||||
|
||||
ax2.cla()
|
||||
ax2.plot(X[dataind])
|
||||
|
||||
ax2.text(0.05, 0.9, 'mu=%1.3f\nsigma=%1.3f' % (xs[dataind], ys[dataind]),
|
||||
transform=ax2.transAxes, va='top')
|
||||
ax2.set_ylim(-0.5, 1.5)
|
||||
self.selected.set_visible(True)
|
||||
self.selected.set_data(xs[dataind], ys[dataind])
|
||||
|
||||
self.text.set_text('selected: %d' % dataind)
|
||||
fig.canvas.draw()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import matplotlib.pyplot as plt
|
||||
# Fixing random state for reproducibility
|
||||
np.random.seed(19680801)
|
||||
|
||||
X = np.random.rand(100, 200)
|
||||
xs = np.mean(X, axis=1)
|
||||
ys = np.std(X, axis=1)
|
||||
|
||||
fig, (ax, ax2) = plt.subplots(2, 1)
|
||||
ax.set_title('click on point to plot time series')
|
||||
line, = ax.plot(xs, ys, 'o', picker=5) # 5 points tolerance
|
||||
|
||||
browser = PointBrowser()
|
||||
|
||||
fig.canvas.mpl_connect('pick_event', browser.onpick)
|
||||
fig.canvas.mpl_connect('key_press_event', browser.onpress)
|
||||
|
||||
plt.show()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: data_browser.py](https://matplotlib.org/_downloads/data_browser.py)
|
||||
- [下载Jupyter notebook: data_browser.ipynb](https://matplotlib.org/_downloads/data_browser.ipynb)
|
||||
@@ -0,0 +1,62 @@
|
||||
# 图轴的进入和离开
|
||||
|
||||
通过更改进入和离开时的框架颜色来说明图形和轴进入和离开事件
|
||||
|
||||
```python
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
|
||||
def enter_axes(event):
|
||||
print('enter_axes', event.inaxes)
|
||||
event.inaxes.patch.set_facecolor('yellow')
|
||||
event.canvas.draw()
|
||||
|
||||
|
||||
def leave_axes(event):
|
||||
print('leave_axes', event.inaxes)
|
||||
event.inaxes.patch.set_facecolor('white')
|
||||
event.canvas.draw()
|
||||
|
||||
|
||||
def enter_figure(event):
|
||||
print('enter_figure', event.canvas.figure)
|
||||
event.canvas.figure.patch.set_facecolor('red')
|
||||
event.canvas.draw()
|
||||
|
||||
|
||||
def leave_figure(event):
|
||||
print('leave_figure', event.canvas.figure)
|
||||
event.canvas.figure.patch.set_facecolor('grey')
|
||||
event.canvas.draw()
|
||||
```
|
||||
|
||||
```python
|
||||
fig1, (ax, ax2) = plt.subplots(2, 1)
|
||||
fig1.suptitle('mouse hover over figure or axes to trigger events')
|
||||
|
||||
fig1.canvas.mpl_connect('figure_enter_event', enter_figure)
|
||||
fig1.canvas.mpl_connect('figure_leave_event', leave_figure)
|
||||
fig1.canvas.mpl_connect('axes_enter_event', enter_axes)
|
||||
fig1.canvas.mpl_connect('axes_leave_event', leave_axes)
|
||||
```
|
||||
|
||||

|
||||
|
||||
```python
|
||||
fig2, (ax, ax2) = plt.subplots(2, 1)
|
||||
fig2.suptitle('mouse hover over figure or axes to trigger events')
|
||||
|
||||
fig2.canvas.mpl_connect('figure_enter_event', enter_figure)
|
||||
fig2.canvas.mpl_connect('figure_leave_event', leave_figure)
|
||||
fig2.canvas.mpl_connect('axes_enter_event', enter_axes)
|
||||
fig2.canvas.mpl_connect('axes_leave_event', leave_axes)
|
||||
|
||||
plt.show()
|
||||
```
|
||||
|
||||

|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: figure_axes_enter_leave.py](https://matplotlib.org/_downloads/figure_axes_enter_leave.py)
|
||||
- [下载Jupyter notebook: figure_axes_enter_leave.ipynb](https://matplotlib.org/_downloads/figure_axes_enter_leave.ipynb)
|
||||
@@ -0,0 +1,19 @@
|
||||
# Ginput 演示
|
||||
|
||||
这提供了交互功能的使用示例,例如ginput。
|
||||
|
||||
```python
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
t = np.arange(10)
|
||||
plt.plot(t, np.sin(t))
|
||||
print("Please click")
|
||||
x = plt.ginput(3)
|
||||
print("clicked", x)
|
||||
plt.show()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: ginput_demo_sgskip.py](https://matplotlib.org/_downloads/ginput_demo_sgskip.py)
|
||||
- [下载Jupyter notebook: ginput_demo_sgskip.ipynb](https://matplotlib.org/_downloads/ginput_demo_sgskip.ipynb)
|
||||
@@ -0,0 +1,97 @@
|
||||
# 交互功能
|
||||
|
||||
这提供了交互功能的使用示例,例如ginput,waitforbuttonpress和手动clabel放置。
|
||||
|
||||
必须使用具有图形用户界面的后端以交互方式运行此脚本(例如,使用GTK3Agg后端,而不是PS后端)。
|
||||
|
||||
另见: ginput_demo.py
|
||||
|
||||
```python
|
||||
import time
|
||||
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
|
||||
def tellme(s):
|
||||
print(s)
|
||||
plt.title(s, fontsize=16)
|
||||
plt.draw()
|
||||
```
|
||||
|
||||
单击三个点定义三角形
|
||||
|
||||
```python
|
||||
plt.clf()
|
||||
plt.axis([-1., 1., -1., 1.])
|
||||
plt.setp(plt.gca(), autoscale_on=False)
|
||||
|
||||
tellme('You will define a triangle, click to begin')
|
||||
|
||||
plt.waitforbuttonpress()
|
||||
|
||||
while True:
|
||||
pts = []
|
||||
while len(pts) < 3:
|
||||
tellme('Select 3 corners with mouse')
|
||||
pts = np.asarray(plt.ginput(3, timeout=-1))
|
||||
if len(pts) < 3:
|
||||
tellme('Too few points, starting over')
|
||||
time.sleep(1) # Wait a second
|
||||
|
||||
ph = plt.fill(pts[:, 0], pts[:, 1], 'r', lw=2)
|
||||
|
||||
tellme('Happy? Key click for yes, mouse click for no')
|
||||
|
||||
if plt.waitforbuttonpress():
|
||||
break
|
||||
|
||||
# Get rid of fill
|
||||
for p in ph:
|
||||
p.remove()
|
||||
```
|
||||
|
||||
现在轮廓根据三角形角的距离 - 只是一个例子
|
||||
|
||||
```python
|
||||
# Define a nice function of distance from individual pts
|
||||
def f(x, y, pts):
|
||||
z = np.zeros_like(x)
|
||||
for p in pts:
|
||||
z = z + 1/(np.sqrt((x - p[0])**2 + (y - p[1])**2))
|
||||
return 1/z
|
||||
|
||||
|
||||
X, Y = np.meshgrid(np.linspace(-1, 1, 51), np.linspace(-1, 1, 51))
|
||||
Z = f(X, Y, pts)
|
||||
|
||||
CS = plt.contour(X, Y, Z, 20)
|
||||
|
||||
tellme('Use mouse to select contour label locations, middle button to finish')
|
||||
CL = plt.clabel(CS, manual=True)
|
||||
```
|
||||
|
||||
现在做一个缩放
|
||||
|
||||
```python
|
||||
tellme('Now do a nested zoom, click to begin')
|
||||
plt.waitforbuttonpress()
|
||||
|
||||
while True:
|
||||
tellme('Select two corners of zoom, middle mouse button to finish')
|
||||
pts = np.asarray(plt.ginput(2, timeout=-1))
|
||||
|
||||
if len(pts) < 2:
|
||||
break
|
||||
|
||||
pts = np.sort(pts, axis=0)
|
||||
plt.axis(pts.T.ravel())
|
||||
|
||||
tellme('All Done!')
|
||||
plt.show()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: ginput_manual_clabel_sgskip.py](https://matplotlib.org/_downloads/ginput_manual_clabel_sgskip.py)
|
||||
- [下载Jupyter notebook: ginput_manual_clabel_sgskip.ipynb](https://matplotlib.org/_downloads/ginput_manual_clabel_sgskip.ipynb)
|
||||
@@ -0,0 +1,52 @@
|
||||
# 图像切片查看器
|
||||
|
||||
滚动三维阵列的二维图像切片。
|
||||
|
||||

|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
|
||||
class IndexTracker(object):
|
||||
def __init__(self, ax, X):
|
||||
self.ax = ax
|
||||
ax.set_title('use scroll wheel to navigate images')
|
||||
|
||||
self.X = X
|
||||
rows, cols, self.slices = X.shape
|
||||
self.ind = self.slices//2
|
||||
|
||||
self.im = ax.imshow(self.X[:, :, self.ind])
|
||||
self.update()
|
||||
|
||||
def onscroll(self, event):
|
||||
print("%s %s" % (event.button, event.step))
|
||||
if event.button == 'up':
|
||||
self.ind = (self.ind + 1) % self.slices
|
||||
else:
|
||||
self.ind = (self.ind - 1) % self.slices
|
||||
self.update()
|
||||
|
||||
def update(self):
|
||||
self.im.set_data(self.X[:, :, self.ind])
|
||||
ax.set_ylabel('slice %s' % self.ind)
|
||||
self.im.axes.figure.canvas.draw()
|
||||
|
||||
|
||||
fig, ax = plt.subplots(1, 1)
|
||||
|
||||
X = np.random.rand(20, 20, 40)
|
||||
|
||||
tracker = IndexTracker(ax, X)
|
||||
|
||||
|
||||
fig.canvas.mpl_connect('scroll_event', tracker.onscroll)
|
||||
plt.show()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: image_slices_viewer.py](https://matplotlib.org/_downloads/image_slices_viewer.py)
|
||||
- [下载Jupyter notebook: image_slices_viewer.ipynb](https://matplotlib.org/_downloads/image_slices_viewer.ipynb)
|
||||
3
Python/matplotlab/gallery/event_handling/index.md
Normal file
3
Python/matplotlab/gallery/event_handling/index.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# 事件处理
|
||||
|
||||
Matplotlib支持使用GUI中立事件模型进行[事件处理](https://matplotlib.org/users/event_handling.html),因此您可以连接到Matplotlib事件,而无需了解Matplotlib最终将插入哪个用户界面。 这有两个好处:你编写的代码将更加可移植,Matplotlib事件就像数据坐标空间和事件发生在哪些轴之类的东西,所以你不必混淆低级转换细节来自画布空间到数据空间。还包括对象拾取示例。
|
||||
38
Python/matplotlab/gallery/event_handling/keypress_demo.md
Normal file
38
Python/matplotlab/gallery/event_handling/keypress_demo.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# 按键演示
|
||||
|
||||
显示如何连接到按键事件
|
||||
|
||||

|
||||
|
||||
```python
|
||||
import sys
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
|
||||
def press(event):
|
||||
print('press', event.key)
|
||||
sys.stdout.flush()
|
||||
if event.key == 'x':
|
||||
visible = xl.get_visible()
|
||||
xl.set_visible(not visible)
|
||||
fig.canvas.draw()
|
||||
|
||||
# Fixing random state for reproducibility
|
||||
np.random.seed(19680801)
|
||||
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
|
||||
fig.canvas.mpl_connect('key_press_event', press)
|
||||
|
||||
ax.plot(np.random.rand(12), np.random.rand(12), 'go')
|
||||
xl = ax.set_xlabel('easy come, easy go')
|
||||
ax.set_title('Press a key')
|
||||
plt.show()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: keypress_demo.py](https://matplotlib.org/_downloads/keypress_demo.py)
|
||||
- [下载Jupyter notebook: keypress_demo.ipynb](https://matplotlib.org/_downloads/keypress_demo.ipynb)
|
||||
92
Python/matplotlab/gallery/event_handling/lasso_demo.md
Normal file
92
Python/matplotlab/gallery/event_handling/lasso_demo.md
Normal file
@@ -0,0 +1,92 @@
|
||||
# 套索演示
|
||||
|
||||
演示如何使用套索选择一组点并获取所选点的索引。回调用于更改所选点的颜色。
|
||||
|
||||
这是一个概念验证实现(尽管它可以按原样使用)。将对API进行一些改进。
|
||||
|
||||

|
||||
|
||||
```python
|
||||
from matplotlib import colors as mcolors, path
|
||||
from matplotlib.collections import RegularPolyCollection
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib.widgets import Lasso
|
||||
import numpy as np
|
||||
|
||||
|
||||
class Datum(object):
|
||||
colorin = mcolors.to_rgba("red")
|
||||
colorout = mcolors.to_rgba("blue")
|
||||
|
||||
def __init__(self, x, y, include=False):
|
||||
self.x = x
|
||||
self.y = y
|
||||
if include:
|
||||
self.color = self.colorin
|
||||
else:
|
||||
self.color = self.colorout
|
||||
|
||||
|
||||
class LassoManager(object):
|
||||
def __init__(self, ax, data):
|
||||
self.axes = ax
|
||||
self.canvas = ax.figure.canvas
|
||||
self.data = data
|
||||
|
||||
self.Nxy = len(data)
|
||||
|
||||
facecolors = [d.color for d in data]
|
||||
self.xys = [(d.x, d.y) for d in data]
|
||||
self.collection = RegularPolyCollection(
|
||||
6, sizes=(100,),
|
||||
facecolors=facecolors,
|
||||
offsets=self.xys,
|
||||
transOffset=ax.transData)
|
||||
|
||||
ax.add_collection(self.collection)
|
||||
|
||||
self.cid = self.canvas.mpl_connect('button_press_event', self.onpress)
|
||||
|
||||
def callback(self, verts):
|
||||
facecolors = self.collection.get_facecolors()
|
||||
p = path.Path(verts)
|
||||
ind = p.contains_points(self.xys)
|
||||
for i in range(len(self.xys)):
|
||||
if ind[i]:
|
||||
facecolors[i] = Datum.colorin
|
||||
else:
|
||||
facecolors[i] = Datum.colorout
|
||||
|
||||
self.canvas.draw_idle()
|
||||
self.canvas.widgetlock.release(self.lasso)
|
||||
del self.lasso
|
||||
|
||||
def onpress(self, event):
|
||||
if self.canvas.widgetlock.locked():
|
||||
return
|
||||
if event.inaxes is None:
|
||||
return
|
||||
self.lasso = Lasso(event.inaxes,
|
||||
(event.xdata, event.ydata),
|
||||
self.callback)
|
||||
# acquire a lock on the widget drawing
|
||||
self.canvas.widgetlock(self.lasso)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
np.random.seed(19680801)
|
||||
|
||||
data = [Datum(*xy) for xy in np.random.rand(100, 2)]
|
||||
ax = plt.axes(xlim=(0, 1), ylim=(0, 1), autoscale_on=False)
|
||||
ax.set_title('Lasso points using left mouse button')
|
||||
|
||||
lman = LassoManager(ax, data)
|
||||
|
||||
plt.show()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: lasso_demo.py](https://matplotlib.org/_downloads/lasso_demo.py)
|
||||
- [下载Jupyter notebook: lasso_demo.ipynb](https://matplotlib.org/_downloads/lasso_demo.ipynb)
|
||||
55
Python/matplotlab/gallery/event_handling/legend_picking.md
Normal file
55
Python/matplotlab/gallery/event_handling/legend_picking.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# 图例选择
|
||||
|
||||
启用图例上的拾取以打开和关闭原始线。
|
||||
|
||||

|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
t = np.arange(0.0, 0.2, 0.1)
|
||||
y1 = 2*np.sin(2*np.pi*t)
|
||||
y2 = 4*np.sin(2*np.pi*2*t)
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
ax.set_title('Click on legend line to toggle line on/off')
|
||||
line1, = ax.plot(t, y1, lw=2, color='red', label='1 HZ')
|
||||
line2, = ax.plot(t, y2, lw=2, color='blue', label='2 HZ')
|
||||
leg = ax.legend(loc='upper left', fancybox=True, shadow=True)
|
||||
leg.get_frame().set_alpha(0.4)
|
||||
|
||||
|
||||
# we will set up a dict mapping legend line to orig line, and enable
|
||||
# picking on the legend line
|
||||
lines = [line1, line2]
|
||||
lined = dict()
|
||||
for legline, origline in zip(leg.get_lines(), lines):
|
||||
legline.set_picker(5) # 5 pts tolerance
|
||||
lined[legline] = origline
|
||||
|
||||
|
||||
def onpick(event):
|
||||
# on the pick event, find the orig line corresponding to the
|
||||
# legend proxy line, and toggle the visibility
|
||||
legline = event.artist
|
||||
origline = lined[legline]
|
||||
vis = not origline.get_visible()
|
||||
origline.set_visible(vis)
|
||||
# Change the alpha on the line in the legend so we can see what lines
|
||||
# have been toggled
|
||||
if vis:
|
||||
legline.set_alpha(1.0)
|
||||
else:
|
||||
legline.set_alpha(0.2)
|
||||
fig.canvas.draw()
|
||||
|
||||
fig.canvas.mpl_connect('pick_event', onpick)
|
||||
|
||||
plt.show()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: legend_picking.py](https://matplotlib.org/_downloads/legend_picking.py)
|
||||
- [下载Jupyter notebook: legend_picking.ipynb](https://matplotlib.org/_downloads/legend_picking.ipynb)
|
||||
65
Python/matplotlab/gallery/event_handling/looking_glass.md
Normal file
65
Python/matplotlab/gallery/event_handling/looking_glass.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# 镜子
|
||||
|
||||
例如,使用鼠标事件模拟用于检查数据的镜子。
|
||||
|
||||

|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.patches as patches
|
||||
|
||||
# Fixing random state for reproducibility
|
||||
np.random.seed(19680801)
|
||||
|
||||
x, y = np.random.rand(2, 200)
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
circ = patches.Circle((0.5, 0.5), 0.25, alpha=0.8, fc='yellow')
|
||||
ax.add_patch(circ)
|
||||
|
||||
|
||||
ax.plot(x, y, alpha=0.2)
|
||||
line, = ax.plot(x, y, alpha=1.0, clip_path=circ)
|
||||
ax.set_title("Left click and drag to move looking glass")
|
||||
|
||||
|
||||
class EventHandler(object):
|
||||
def __init__(self):
|
||||
fig.canvas.mpl_connect('button_press_event', self.onpress)
|
||||
fig.canvas.mpl_connect('button_release_event', self.onrelease)
|
||||
fig.canvas.mpl_connect('motion_notify_event', self.onmove)
|
||||
self.x0, self.y0 = circ.center
|
||||
self.pressevent = None
|
||||
|
||||
def onpress(self, event):
|
||||
if event.inaxes != ax:
|
||||
return
|
||||
|
||||
if not circ.contains(event)[0]:
|
||||
return
|
||||
|
||||
self.pressevent = event
|
||||
|
||||
def onrelease(self, event):
|
||||
self.pressevent = None
|
||||
self.x0, self.y0 = circ.center
|
||||
|
||||
def onmove(self, event):
|
||||
if self.pressevent is None or event.inaxes != self.pressevent.inaxes:
|
||||
return
|
||||
|
||||
dx = event.xdata - self.pressevent.xdata
|
||||
dy = event.ydata - self.pressevent.ydata
|
||||
circ.center = self.x0 + dx, self.y0 + dy
|
||||
line.set_clip_path(circ)
|
||||
fig.canvas.draw()
|
||||
|
||||
handler = EventHandler()
|
||||
plt.show()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: looking_glass.py](https://matplotlib.org/_downloads/looking_glass.py)
|
||||
- [下载Jupyter notebook: looking_glass.ipynb](https://matplotlib.org/_downloads/looking_glass.ipynb)
|
||||
164
Python/matplotlab/gallery/event_handling/path_editor.md
Normal file
164
Python/matplotlab/gallery/event_handling/path_editor.md
Normal file
@@ -0,0 +1,164 @@
|
||||
# 路径编辑器
|
||||
|
||||
跨GUI共享事件。
|
||||
|
||||
此示例演示了使用Matplotlib事件处理与画布上的对象进行交互和修改对象的跨GUI应用程序。
|
||||
|
||||

|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
import matplotlib.path as mpath
|
||||
import matplotlib.patches as mpatches
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
Path = mpath.Path
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
|
||||
pathdata = [
|
||||
(Path.MOVETO, (1.58, -2.57)),
|
||||
(Path.CURVE4, (0.35, -1.1)),
|
||||
(Path.CURVE4, (-1.75, 2.0)),
|
||||
(Path.CURVE4, (0.375, 2.0)),
|
||||
(Path.LINETO, (0.85, 1.15)),
|
||||
(Path.CURVE4, (2.2, 3.2)),
|
||||
(Path.CURVE4, (3, 0.05)),
|
||||
(Path.CURVE4, (2.0, -0.5)),
|
||||
(Path.CLOSEPOLY, (1.58, -2.57)),
|
||||
]
|
||||
|
||||
codes, verts = zip(*pathdata)
|
||||
path = mpath.Path(verts, codes)
|
||||
patch = mpatches.PathPatch(path, facecolor='green', edgecolor='yellow', alpha=0.5)
|
||||
ax.add_patch(patch)
|
||||
|
||||
|
||||
class PathInteractor(object):
|
||||
"""
|
||||
An path editor.
|
||||
|
||||
Key-bindings
|
||||
|
||||
't' toggle vertex markers on and off. When vertex markers are on,
|
||||
you can move them, delete them
|
||||
|
||||
|
||||
"""
|
||||
|
||||
showverts = True
|
||||
epsilon = 5 # max pixel distance to count as a vertex hit
|
||||
|
||||
def __init__(self, pathpatch):
|
||||
|
||||
self.ax = pathpatch.axes
|
||||
canvas = self.ax.figure.canvas
|
||||
self.pathpatch = pathpatch
|
||||
self.pathpatch.set_animated(True)
|
||||
|
||||
x, y = zip(*self.pathpatch.get_path().vertices)
|
||||
|
||||
self.line, = ax.plot(x, y, marker='o', markerfacecolor='r', animated=True)
|
||||
|
||||
self._ind = None # the active vert
|
||||
|
||||
canvas.mpl_connect('draw_event', self.draw_callback)
|
||||
canvas.mpl_connect('button_press_event', self.button_press_callback)
|
||||
canvas.mpl_connect('key_press_event', self.key_press_callback)
|
||||
canvas.mpl_connect('button_release_event', self.button_release_callback)
|
||||
canvas.mpl_connect('motion_notify_event', self.motion_notify_callback)
|
||||
self.canvas = canvas
|
||||
|
||||
def draw_callback(self, event):
|
||||
self.background = self.canvas.copy_from_bbox(self.ax.bbox)
|
||||
self.ax.draw_artist(self.pathpatch)
|
||||
self.ax.draw_artist(self.line)
|
||||
self.canvas.blit(self.ax.bbox)
|
||||
|
||||
def pathpatch_changed(self, pathpatch):
|
||||
'this method is called whenever the pathpatchgon object is called'
|
||||
# only copy the artist props to the line (except visibility)
|
||||
vis = self.line.get_visible()
|
||||
plt.Artist.update_from(self.line, pathpatch)
|
||||
self.line.set_visible(vis) # don't use the pathpatch visibility state
|
||||
|
||||
def get_ind_under_point(self, event):
|
||||
'get the index of the vertex under point if within epsilon tolerance'
|
||||
|
||||
# display coords
|
||||
xy = np.asarray(self.pathpatch.get_path().vertices)
|
||||
xyt = self.pathpatch.get_transform().transform(xy)
|
||||
xt, yt = xyt[:, 0], xyt[:, 1]
|
||||
d = np.sqrt((xt - event.x)**2 + (yt - event.y)**2)
|
||||
ind = d.argmin()
|
||||
|
||||
if d[ind] >= self.epsilon:
|
||||
ind = None
|
||||
|
||||
return ind
|
||||
|
||||
def button_press_callback(self, event):
|
||||
'whenever a mouse button is pressed'
|
||||
if not self.showverts:
|
||||
return
|
||||
if event.inaxes is None:
|
||||
return
|
||||
if event.button != 1:
|
||||
return
|
||||
self._ind = self.get_ind_under_point(event)
|
||||
|
||||
def button_release_callback(self, event):
|
||||
'whenever a mouse button is released'
|
||||
if not self.showverts:
|
||||
return
|
||||
if event.button != 1:
|
||||
return
|
||||
self._ind = None
|
||||
|
||||
def key_press_callback(self, event):
|
||||
'whenever a key is pressed'
|
||||
if not event.inaxes:
|
||||
return
|
||||
if event.key == 't':
|
||||
self.showverts = not self.showverts
|
||||
self.line.set_visible(self.showverts)
|
||||
if not self.showverts:
|
||||
self._ind = None
|
||||
|
||||
self.canvas.draw()
|
||||
|
||||
def motion_notify_callback(self, event):
|
||||
'on mouse movement'
|
||||
if not self.showverts:
|
||||
return
|
||||
if self._ind is None:
|
||||
return
|
||||
if event.inaxes is None:
|
||||
return
|
||||
if event.button != 1:
|
||||
return
|
||||
x, y = event.xdata, event.ydata
|
||||
|
||||
vertices = self.pathpatch.get_path().vertices
|
||||
|
||||
vertices[self._ind] = x, y
|
||||
self.line.set_data(zip(*vertices))
|
||||
|
||||
self.canvas.restore_region(self.background)
|
||||
self.ax.draw_artist(self.pathpatch)
|
||||
self.ax.draw_artist(self.line)
|
||||
self.canvas.blit(self.ax.bbox)
|
||||
|
||||
|
||||
interactor = PathInteractor(patch)
|
||||
ax.set_title('drag vertices to update path')
|
||||
ax.set_xlim(-3, 4)
|
||||
ax.set_ylim(-3, 4)
|
||||
|
||||
plt.show()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: path_editor.py](https://matplotlib.org/_downloads/path_editor.py)
|
||||
- [下载Jupyter notebook: path_editor.ipynb](https://matplotlib.org/_downloads/path_editor.ipynb)
|
||||
154
Python/matplotlab/gallery/event_handling/pick_event_demo.md
Normal file
154
Python/matplotlab/gallery/event_handling/pick_event_demo.md
Normal file
@@ -0,0 +1,154 @@
|
||||
# 选择事件演示
|
||||
|
||||
您可以通过设置艺术家的“选择器”属性来启用拾取(例如,matplotlib Line2D,Text,Patch,Polygon,AxesImage等...)
|
||||
|
||||
选择器属性有多种含义
|
||||
|
||||
- None - 此艺术家对象的选择功能已停用(默认)
|
||||
- boolean - 如果为True,则启用拾取,如果鼠标事件在艺术家上方,艺术家将触发拾取事件
|
||||
- float - 如果选择器是一个数字,则它被解释为以点为单位的epsilon容差,如果事件的数据在鼠标事件的epsilon内,则艺术家将触发事件。 对于某些艺术家(如线条和补丁集合),艺术家可能会为生成的挑选事件提供其他数据,例如,挑选事件的epsilon中的数据索引
|
||||
- function - 如果选择器是可调用的,则它是用户提供的函数,用于确定艺术家是否被鼠标事件命中。
|
||||
|
||||
hit, props = picker(artist, mouseevent)
|
||||
|
||||
确定命中测试。 如果鼠标事件在艺术家上方,则返回hit = True,props是要添加到PickEvent属性的属性字典
|
||||
|
||||
通过设置“选取器”属性启用艺术家进行拾取后,您需要连接到图形画布pick_event以获取鼠标按下事件的拾取回调。 例如,
|
||||
|
||||
def pick_handler(event):
|
||||
|
||||
mouseevent = event.mouseevent artist = event.artist # now do something with this...
|
||||
|
||||
传递给回调的pick事件(matplotlib.backend_bases.PickEvent)始终使用两个属性触发:
|
||||
|
||||
- mouseevent - 生成拾取事件的鼠标事件。 鼠标事件又具有x和y(显示空间中的坐标,如左下角的像素)和xdata,ydata(数据空间中的坐标)等属性。 此外,您可以获取有关按下哪些按钮,按下哪些键,鼠标所在的轴等的信息。有关详细信息,请参阅matplotlib.backend_bases.MouseEvent。
|
||||
|
||||
- artist - 生成pick事件的matplotlib.artist。
|
||||
|
||||
此外,某些艺术家(如Line2D和PatchCollection)可能会将其他元数据(如索引)附加到符合选择器条件的数据中(例如,行中指定的epsilon容差范围内的所有点)
|
||||
|
||||
以下示例说明了这些方法中的每一种。
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
```python
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib.lines import Line2D
|
||||
from matplotlib.patches import Rectangle
|
||||
from matplotlib.text import Text
|
||||
from matplotlib.image import AxesImage
|
||||
import numpy as np
|
||||
from numpy.random import rand
|
||||
|
||||
if 1: # simple picking, lines, rectangles and text
|
||||
fig, (ax1, ax2) = plt.subplots(2, 1)
|
||||
ax1.set_title('click on points, rectangles or text', picker=True)
|
||||
ax1.set_ylabel('ylabel', picker=True, bbox=dict(facecolor='red'))
|
||||
line, = ax1.plot(rand(100), 'o', picker=5) # 5 points tolerance
|
||||
|
||||
# pick the rectangle
|
||||
bars = ax2.bar(range(10), rand(10), picker=True)
|
||||
for label in ax2.get_xticklabels(): # make the xtick labels pickable
|
||||
label.set_picker(True)
|
||||
|
||||
def onpick1(event):
|
||||
if isinstance(event.artist, Line2D):
|
||||
thisline = event.artist
|
||||
xdata = thisline.get_xdata()
|
||||
ydata = thisline.get_ydata()
|
||||
ind = event.ind
|
||||
print('onpick1 line:', zip(np.take(xdata, ind), np.take(ydata, ind)))
|
||||
elif isinstance(event.artist, Rectangle):
|
||||
patch = event.artist
|
||||
print('onpick1 patch:', patch.get_path())
|
||||
elif isinstance(event.artist, Text):
|
||||
text = event.artist
|
||||
print('onpick1 text:', text.get_text())
|
||||
|
||||
fig.canvas.mpl_connect('pick_event', onpick1)
|
||||
|
||||
if 1: # picking with a custom hit test function
|
||||
# you can define custom pickers by setting picker to a callable
|
||||
# function. The function has the signature
|
||||
#
|
||||
# hit, props = func(artist, mouseevent)
|
||||
#
|
||||
# to determine the hit test. if the mouse event is over the artist,
|
||||
# return hit=True and props is a dictionary of
|
||||
# properties you want added to the PickEvent attributes
|
||||
|
||||
def line_picker(line, mouseevent):
|
||||
"""
|
||||
find the points within a certain distance from the mouseclick in
|
||||
data coords and attach some extra attributes, pickx and picky
|
||||
which are the data points that were picked
|
||||
"""
|
||||
if mouseevent.xdata is None:
|
||||
return False, dict()
|
||||
xdata = line.get_xdata()
|
||||
ydata = line.get_ydata()
|
||||
maxd = 0.05
|
||||
d = np.sqrt((xdata - mouseevent.xdata)**2. + (ydata - mouseevent.ydata)**2.)
|
||||
|
||||
ind = np.nonzero(np.less_equal(d, maxd))
|
||||
if len(ind):
|
||||
pickx = np.take(xdata, ind)
|
||||
picky = np.take(ydata, ind)
|
||||
props = dict(ind=ind, pickx=pickx, picky=picky)
|
||||
return True, props
|
||||
else:
|
||||
return False, dict()
|
||||
|
||||
def onpick2(event):
|
||||
print('onpick2 line:', event.pickx, event.picky)
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
ax.set_title('custom picker for line data')
|
||||
line, = ax.plot(rand(100), rand(100), 'o', picker=line_picker)
|
||||
fig.canvas.mpl_connect('pick_event', onpick2)
|
||||
|
||||
|
||||
if 1: # picking on a scatter plot (matplotlib.collections.RegularPolyCollection)
|
||||
|
||||
x, y, c, s = rand(4, 100)
|
||||
|
||||
def onpick3(event):
|
||||
ind = event.ind
|
||||
print('onpick3 scatter:', ind, np.take(x, ind), np.take(y, ind))
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
col = ax.scatter(x, y, 100*s, c, picker=True)
|
||||
#fig.savefig('pscoll.eps')
|
||||
fig.canvas.mpl_connect('pick_event', onpick3)
|
||||
|
||||
if 1: # picking images (matplotlib.image.AxesImage)
|
||||
fig, ax = plt.subplots()
|
||||
im1 = ax.imshow(rand(10, 5), extent=(1, 2, 1, 2), picker=True)
|
||||
im2 = ax.imshow(rand(5, 10), extent=(3, 4, 1, 2), picker=True)
|
||||
im3 = ax.imshow(rand(20, 25), extent=(1, 2, 3, 4), picker=True)
|
||||
im4 = ax.imshow(rand(30, 12), extent=(3, 4, 3, 4), picker=True)
|
||||
ax.axis([0, 5, 0, 5])
|
||||
|
||||
def onpick4(event):
|
||||
artist = event.artist
|
||||
if isinstance(artist, AxesImage):
|
||||
im = artist
|
||||
A = im.get_array()
|
||||
print('onpick4 image', A.shape)
|
||||
|
||||
fig.canvas.mpl_connect('pick_event', onpick4)
|
||||
|
||||
|
||||
plt.show()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: pick_event_demo.py](https://matplotlib.org/_downloads/pick_event_demo.py)
|
||||
- [下载Jupyter notebook: pick_event_demo.ipynb](https://matplotlib.org/_downloads/pick_event_demo.ipynb)
|
||||
47
Python/matplotlab/gallery/event_handling/pick_event_demo2.md
Normal file
47
Python/matplotlab/gallery/event_handling/pick_event_demo2.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# 选择事件演示2
|
||||
|
||||
计算100个数据集的平均值和标准差(stddev),并绘制平均值vs stddev。单击其中一个mu,sigma点时,绘制生成均值和stddev的数据集中的原始数据。
|
||||
|
||||

|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
|
||||
X = np.random.rand(100, 1000)
|
||||
xs = np.mean(X, axis=1)
|
||||
ys = np.std(X, axis=1)
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
ax.set_title('click on point to plot time series')
|
||||
line, = ax.plot(xs, ys, 'o', picker=5) # 5 points tolerance
|
||||
|
||||
|
||||
def onpick(event):
|
||||
|
||||
if event.artist != line:
|
||||
return True
|
||||
|
||||
N = len(event.ind)
|
||||
if not N:
|
||||
return True
|
||||
|
||||
figi, axs = plt.subplots(N, squeeze=False)
|
||||
for ax, dataind in zip(axs.flat, event.ind):
|
||||
ax.plot(X[dataind])
|
||||
ax.text(.05, .9, 'mu=%1.3f\nsigma=%1.3f' % (xs[dataind], ys[dataind]),
|
||||
transform=ax.transAxes, va='top')
|
||||
ax.set_ylim(-0.5, 1.5)
|
||||
figi.show()
|
||||
return True
|
||||
|
||||
fig.canvas.mpl_connect('pick_event', onpick)
|
||||
|
||||
plt.show()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: pick_event_demo2.py](https://matplotlib.org/_downloads/pick_event_demo2.py)
|
||||
- [下载Jupyter notebook: pick_event_demo2.ipynb](https://matplotlib.org/_downloads/pick_event_demo2.ipynb)
|
||||
291
Python/matplotlab/gallery/event_handling/pipong.md
Normal file
291
Python/matplotlab/gallery/event_handling/pipong.md
Normal file
@@ -0,0 +1,291 @@
|
||||
# Pipong
|
||||
|
||||
一个基于Matplotlib的Pong游戏,说明了一种编写交互动画的方法,它很容易移植到多个后端pipong.py由Paul Ivanov撰写<http://pirsquared.org>
|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
from numpy.random import randn, randint
|
||||
from matplotlib.font_manager import FontProperties
|
||||
|
||||
instructions = """
|
||||
Player A: Player B:
|
||||
'e' up 'i'
|
||||
'd' down 'k'
|
||||
|
||||
press 't' -- close these instructions
|
||||
(animation will be much faster)
|
||||
press 'a' -- add a puck
|
||||
press 'A' -- remove a puck
|
||||
press '1' -- slow down all pucks
|
||||
press '2' -- speed up all pucks
|
||||
press '3' -- slow down distractors
|
||||
press '4' -- speed up distractors
|
||||
press ' ' -- reset the first puck
|
||||
press 'n' -- toggle distractors on/off
|
||||
press 'g' -- toggle the game on/off
|
||||
|
||||
"""
|
||||
|
||||
|
||||
class Pad(object):
|
||||
def __init__(self, disp, x, y, type='l'):
|
||||
self.disp = disp
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.w = .3
|
||||
self.score = 0
|
||||
self.xoffset = 0.3
|
||||
self.yoffset = 0.1
|
||||
if type == 'r':
|
||||
self.xoffset *= -1.0
|
||||
|
||||
if type == 'l' or type == 'r':
|
||||
self.signx = -1.0
|
||||
self.signy = 1.0
|
||||
else:
|
||||
self.signx = 1.0
|
||||
self.signy = -1.0
|
||||
|
||||
def contains(self, loc):
|
||||
return self.disp.get_bbox().contains(loc.x, loc.y)
|
||||
|
||||
|
||||
class Puck(object):
|
||||
def __init__(self, disp, pad, field):
|
||||
self.vmax = .2
|
||||
self.disp = disp
|
||||
self.field = field
|
||||
self._reset(pad)
|
||||
|
||||
def _reset(self, pad):
|
||||
self.x = pad.x + pad.xoffset
|
||||
if pad.y < 0:
|
||||
self.y = pad.y + pad.yoffset
|
||||
else:
|
||||
self.y = pad.y - pad.yoffset
|
||||
self.vx = pad.x - self.x
|
||||
self.vy = pad.y + pad.w/2 - self.y
|
||||
self._speedlimit()
|
||||
self._slower()
|
||||
self._slower()
|
||||
|
||||
def update(self, pads):
|
||||
self.x += self.vx
|
||||
self.y += self.vy
|
||||
for pad in pads:
|
||||
if pad.contains(self):
|
||||
self.vx *= 1.2 * pad.signx
|
||||
self.vy *= 1.2 * pad.signy
|
||||
fudge = .001
|
||||
# probably cleaner with something like...
|
||||
if self.x < fudge:
|
||||
pads[1].score += 1
|
||||
self._reset(pads[0])
|
||||
return True
|
||||
if self.x > 7 - fudge:
|
||||
pads[0].score += 1
|
||||
self._reset(pads[1])
|
||||
return True
|
||||
if self.y < -1 + fudge or self.y > 1 - fudge:
|
||||
self.vy *= -1.0
|
||||
# add some randomness, just to make it interesting
|
||||
self.vy -= (randn()/300.0 + 1/300.0) * np.sign(self.vy)
|
||||
self._speedlimit()
|
||||
return False
|
||||
|
||||
def _slower(self):
|
||||
self.vx /= 5.0
|
||||
self.vy /= 5.0
|
||||
|
||||
def _faster(self):
|
||||
self.vx *= 5.0
|
||||
self.vy *= 5.0
|
||||
|
||||
def _speedlimit(self):
|
||||
if self.vx > self.vmax:
|
||||
self.vx = self.vmax
|
||||
if self.vx < -self.vmax:
|
||||
self.vx = -self.vmax
|
||||
|
||||
if self.vy > self.vmax:
|
||||
self.vy = self.vmax
|
||||
if self.vy < -self.vmax:
|
||||
self.vy = -self.vmax
|
||||
|
||||
|
||||
class Game(object):
|
||||
def __init__(self, ax):
|
||||
# create the initial line
|
||||
self.ax = ax
|
||||
ax.set_ylim([-1, 1])
|
||||
ax.set_xlim([0, 7])
|
||||
padAx = 0
|
||||
padBx = .50
|
||||
padAy = padBy = .30
|
||||
padBx += 6.3
|
||||
|
||||
# pads
|
||||
pA, = self.ax.barh(padAy, .2,
|
||||
height=.3, color='k', alpha=.5, edgecolor='b',
|
||||
lw=2, label="Player B",
|
||||
animated=True)
|
||||
pB, = self.ax.barh(padBy, .2,
|
||||
height=.3, left=padBx, color='k', alpha=.5,
|
||||
edgecolor='r', lw=2, label="Player A",
|
||||
animated=True)
|
||||
|
||||
# distractors
|
||||
self.x = np.arange(0, 2.22*np.pi, 0.01)
|
||||
self.line, = self.ax.plot(self.x, np.sin(self.x), "r",
|
||||
animated=True, lw=4)
|
||||
self.line2, = self.ax.plot(self.x, np.cos(self.x), "g",
|
||||
animated=True, lw=4)
|
||||
self.line3, = self.ax.plot(self.x, np.cos(self.x), "g",
|
||||
animated=True, lw=4)
|
||||
self.line4, = self.ax.plot(self.x, np.cos(self.x), "r",
|
||||
animated=True, lw=4)
|
||||
|
||||
# center line
|
||||
self.centerline, = self.ax.plot([3.5, 3.5], [1, -1], 'k',
|
||||
alpha=.5, animated=True, lw=8)
|
||||
|
||||
# puck (s)
|
||||
self.puckdisp = self.ax.scatter([1], [1], label='_nolegend_',
|
||||
s=200, c='g',
|
||||
alpha=.9, animated=True)
|
||||
|
||||
self.canvas = self.ax.figure.canvas
|
||||
self.background = None
|
||||
self.cnt = 0
|
||||
self.distract = True
|
||||
self.res = 100.0
|
||||
self.on = False
|
||||
self.inst = True # show instructions from the beginning
|
||||
self.background = None
|
||||
self.pads = []
|
||||
self.pads.append(Pad(pA, padAx, padAy))
|
||||
self.pads.append(Pad(pB, padBx, padBy, 'r'))
|
||||
self.pucks = []
|
||||
self.i = self.ax.annotate(instructions, (.5, 0.5),
|
||||
name='monospace',
|
||||
verticalalignment='center',
|
||||
horizontalalignment='center',
|
||||
multialignment='left',
|
||||
textcoords='axes fraction',
|
||||
animated=False)
|
||||
self.canvas.mpl_connect('key_press_event', self.key_press)
|
||||
|
||||
def draw(self, evt):
|
||||
draw_artist = self.ax.draw_artist
|
||||
if self.background is None:
|
||||
self.background = self.canvas.copy_from_bbox(self.ax.bbox)
|
||||
|
||||
# restore the clean slate background
|
||||
self.canvas.restore_region(self.background)
|
||||
|
||||
# show the distractors
|
||||
if self.distract:
|
||||
self.line.set_ydata(np.sin(self.x + self.cnt/self.res))
|
||||
self.line2.set_ydata(np.cos(self.x - self.cnt/self.res))
|
||||
self.line3.set_ydata(np.tan(self.x + self.cnt/self.res))
|
||||
self.line4.set_ydata(np.tan(self.x - self.cnt/self.res))
|
||||
draw_artist(self.line)
|
||||
draw_artist(self.line2)
|
||||
draw_artist(self.line3)
|
||||
draw_artist(self.line4)
|
||||
|
||||
# pucks and pads
|
||||
if self.on:
|
||||
self.ax.draw_artist(self.centerline)
|
||||
for pad in self.pads:
|
||||
pad.disp.set_y(pad.y)
|
||||
pad.disp.set_x(pad.x)
|
||||
self.ax.draw_artist(pad.disp)
|
||||
|
||||
for puck in self.pucks:
|
||||
if puck.update(self.pads):
|
||||
# we only get here if someone scored
|
||||
self.pads[0].disp.set_label(
|
||||
" " + str(self.pads[0].score))
|
||||
self.pads[1].disp.set_label(
|
||||
" " + str(self.pads[1].score))
|
||||
self.ax.legend(loc='center', framealpha=.2,
|
||||
facecolor='0.5',
|
||||
prop=FontProperties(size='xx-large',
|
||||
weight='bold'))
|
||||
|
||||
self.background = None
|
||||
self.ax.figure.canvas.draw_idle()
|
||||
return True
|
||||
puck.disp.set_offsets([[puck.x, puck.y]])
|
||||
self.ax.draw_artist(puck.disp)
|
||||
|
||||
# just redraw the axes rectangle
|
||||
self.canvas.blit(self.ax.bbox)
|
||||
self.canvas.flush_events()
|
||||
if self.cnt == 50000:
|
||||
# just so we don't get carried away
|
||||
print("...and you've been playing for too long!!!")
|
||||
plt.close()
|
||||
|
||||
self.cnt += 1
|
||||
return True
|
||||
|
||||
def key_press(self, event):
|
||||
if event.key == '3':
|
||||
self.res *= 5.0
|
||||
if event.key == '4':
|
||||
self.res /= 5.0
|
||||
|
||||
if event.key == 'e':
|
||||
self.pads[0].y += .1
|
||||
if self.pads[0].y > 1 - .3:
|
||||
self.pads[0].y = 1 - .3
|
||||
if event.key == 'd':
|
||||
self.pads[0].y -= .1
|
||||
if self.pads[0].y < -1:
|
||||
self.pads[0].y = -1
|
||||
|
||||
if event.key == 'i':
|
||||
self.pads[1].y += .1
|
||||
if self.pads[1].y > 1 - .3:
|
||||
self.pads[1].y = 1 - .3
|
||||
if event.key == 'k':
|
||||
self.pads[1].y -= .1
|
||||
if self.pads[1].y < -1:
|
||||
self.pads[1].y = -1
|
||||
|
||||
if event.key == 'a':
|
||||
self.pucks.append(Puck(self.puckdisp,
|
||||
self.pads[randint(2)],
|
||||
self.ax.bbox))
|
||||
if event.key == 'A' and len(self.pucks):
|
||||
self.pucks.pop()
|
||||
if event.key == ' ' and len(self.pucks):
|
||||
self.pucks[0]._reset(self.pads[randint(2)])
|
||||
if event.key == '1':
|
||||
for p in self.pucks:
|
||||
p._slower()
|
||||
if event.key == '2':
|
||||
for p in self.pucks:
|
||||
p._faster()
|
||||
|
||||
if event.key == 'n':
|
||||
self.distract = not self.distract
|
||||
|
||||
if event.key == 'g':
|
||||
self.on = not self.on
|
||||
if event.key == 't':
|
||||
self.inst = not self.inst
|
||||
self.i.set_visible(not self.i.get_visible())
|
||||
self.background = None
|
||||
self.canvas.draw_idle()
|
||||
if event.key == 'q':
|
||||
plt.close()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: pipong.py](https://matplotlib.org/_downloads/pipong.py)
|
||||
- [下载Jupyter notebook: pipong.ipynb](https://matplotlib.org/_downloads/pipong.ipynb)
|
||||
187
Python/matplotlab/gallery/event_handling/poly_editor.md
Normal file
187
Python/matplotlab/gallery/event_handling/poly_editor.md
Normal file
@@ -0,0 +1,187 @@
|
||||
# 综合编辑器
|
||||
|
||||
这是一个示例,展示如何使用Matplotlib事件处理来构建跨GUI应用程序,以与画布上的对象进行交互。
|
||||
|
||||

|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
from matplotlib.lines import Line2D
|
||||
from matplotlib.artist import Artist
|
||||
from matplotlib.mlab import dist_point_to_segment
|
||||
|
||||
|
||||
class PolygonInteractor(object):
|
||||
"""
|
||||
A polygon editor.
|
||||
|
||||
Key-bindings
|
||||
|
||||
't' toggle vertex markers on and off. When vertex markers are on,
|
||||
you can move them, delete them
|
||||
|
||||
'd' delete the vertex under point
|
||||
|
||||
'i' insert a vertex at point. You must be within epsilon of the
|
||||
line connecting two existing vertices
|
||||
|
||||
"""
|
||||
|
||||
showverts = True
|
||||
epsilon = 5 # max pixel distance to count as a vertex hit
|
||||
|
||||
def __init__(self, ax, poly):
|
||||
if poly.figure is None:
|
||||
raise RuntimeError('You must first add the polygon to a figure '
|
||||
'or canvas before defining the interactor')
|
||||
self.ax = ax
|
||||
canvas = poly.figure.canvas
|
||||
self.poly = poly
|
||||
|
||||
x, y = zip(*self.poly.xy)
|
||||
self.line = Line2D(x, y,
|
||||
marker='o', markerfacecolor='r',
|
||||
animated=True)
|
||||
self.ax.add_line(self.line)
|
||||
|
||||
self.cid = self.poly.add_callback(self.poly_changed)
|
||||
self._ind = None # the active vert
|
||||
|
||||
canvas.mpl_connect('draw_event', self.draw_callback)
|
||||
canvas.mpl_connect('button_press_event', self.button_press_callback)
|
||||
canvas.mpl_connect('key_press_event', self.key_press_callback)
|
||||
canvas.mpl_connect('button_release_event', self.button_release_callback)
|
||||
canvas.mpl_connect('motion_notify_event', self.motion_notify_callback)
|
||||
self.canvas = canvas
|
||||
|
||||
def draw_callback(self, event):
|
||||
self.background = self.canvas.copy_from_bbox(self.ax.bbox)
|
||||
self.ax.draw_artist(self.poly)
|
||||
self.ax.draw_artist(self.line)
|
||||
# do not need to blit here, this will fire before the screen is
|
||||
# updated
|
||||
|
||||
def poly_changed(self, poly):
|
||||
'this method is called whenever the polygon object is called'
|
||||
# only copy the artist props to the line (except visibility)
|
||||
vis = self.line.get_visible()
|
||||
Artist.update_from(self.line, poly)
|
||||
self.line.set_visible(vis) # don't use the poly visibility state
|
||||
|
||||
def get_ind_under_point(self, event):
|
||||
'get the index of the vertex under point if within epsilon tolerance'
|
||||
|
||||
# display coords
|
||||
xy = np.asarray(self.poly.xy)
|
||||
xyt = self.poly.get_transform().transform(xy)
|
||||
xt, yt = xyt[:, 0], xyt[:, 1]
|
||||
d = np.hypot(xt - event.x, yt - event.y)
|
||||
indseq, = np.nonzero(d == d.min())
|
||||
ind = indseq[0]
|
||||
|
||||
if d[ind] >= self.epsilon:
|
||||
ind = None
|
||||
|
||||
return ind
|
||||
|
||||
def button_press_callback(self, event):
|
||||
'whenever a mouse button is pressed'
|
||||
if not self.showverts:
|
||||
return
|
||||
if event.inaxes is None:
|
||||
return
|
||||
if event.button != 1:
|
||||
return
|
||||
self._ind = self.get_ind_under_point(event)
|
||||
|
||||
def button_release_callback(self, event):
|
||||
'whenever a mouse button is released'
|
||||
if not self.showverts:
|
||||
return
|
||||
if event.button != 1:
|
||||
return
|
||||
self._ind = None
|
||||
|
||||
def key_press_callback(self, event):
|
||||
'whenever a key is pressed'
|
||||
if not event.inaxes:
|
||||
return
|
||||
if event.key == 't':
|
||||
self.showverts = not self.showverts
|
||||
self.line.set_visible(self.showverts)
|
||||
if not self.showverts:
|
||||
self._ind = None
|
||||
elif event.key == 'd':
|
||||
ind = self.get_ind_under_point(event)
|
||||
if ind is not None:
|
||||
self.poly.xy = np.delete(self.poly.xy,
|
||||
ind, axis=0)
|
||||
self.line.set_data(zip(*self.poly.xy))
|
||||
elif event.key == 'i':
|
||||
xys = self.poly.get_transform().transform(self.poly.xy)
|
||||
p = event.x, event.y # display coords
|
||||
for i in range(len(xys) - 1):
|
||||
s0 = xys[i]
|
||||
s1 = xys[i + 1]
|
||||
d = dist_point_to_segment(p, s0, s1)
|
||||
if d <= self.epsilon:
|
||||
self.poly.xy = np.insert(
|
||||
self.poly.xy, i+1,
|
||||
[event.xdata, event.ydata],
|
||||
axis=0)
|
||||
self.line.set_data(zip(*self.poly.xy))
|
||||
break
|
||||
if self.line.stale:
|
||||
self.canvas.draw_idle()
|
||||
|
||||
def motion_notify_callback(self, event):
|
||||
'on mouse movement'
|
||||
if not self.showverts:
|
||||
return
|
||||
if self._ind is None:
|
||||
return
|
||||
if event.inaxes is None:
|
||||
return
|
||||
if event.button != 1:
|
||||
return
|
||||
x, y = event.xdata, event.ydata
|
||||
|
||||
self.poly.xy[self._ind] = x, y
|
||||
if self._ind == 0:
|
||||
self.poly.xy[-1] = x, y
|
||||
elif self._ind == len(self.poly.xy) - 1:
|
||||
self.poly.xy[0] = x, y
|
||||
self.line.set_data(zip(*self.poly.xy))
|
||||
|
||||
self.canvas.restore_region(self.background)
|
||||
self.ax.draw_artist(self.poly)
|
||||
self.ax.draw_artist(self.line)
|
||||
self.canvas.blit(self.ax.bbox)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib.patches import Polygon
|
||||
|
||||
theta = np.arange(0, 2*np.pi, 0.1)
|
||||
r = 1.5
|
||||
|
||||
xs = r * np.cos(theta)
|
||||
ys = r * np.sin(theta)
|
||||
|
||||
poly = Polygon(np.column_stack([xs, ys]), animated=True)
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
ax.add_patch(poly)
|
||||
p = PolygonInteractor(ax, poly)
|
||||
|
||||
ax.set_title('Click and drag a point to move it')
|
||||
ax.set_xlim((-2, 2))
|
||||
ax.set_ylim((-2, 2))
|
||||
plt.show()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: poly_editor.py](https://matplotlib.org/_downloads/poly_editor.py)
|
||||
- [下载Jupyter notebook: poly_editor.ipynb](https://matplotlib.org/_downloads/poly_editor.ipynb)
|
||||
54
Python/matplotlab/gallery/event_handling/pong_sgskip.md
Normal file
54
Python/matplotlab/gallery/event_handling/pong_sgskip.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# Pong
|
||||
|
||||
一个使用Matplotlib的小游戏演示。
|
||||
|
||||
此示例需要[pipong.py](https://matplotlib.org/_downloads/9a2d2c527d869cd1b03d9560d75d6a71/pipong.py)
|
||||
|
||||
```python
|
||||
import time
|
||||
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import pipong
|
||||
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
canvas = ax.figure.canvas
|
||||
animation = pipong.Game(ax)
|
||||
|
||||
# disable the default key bindings
|
||||
if fig.canvas.manager.key_press_handler_id is not None:
|
||||
canvas.mpl_disconnect(fig.canvas.manager.key_press_handler_id)
|
||||
|
||||
|
||||
# reset the blitting background on redraw
|
||||
def handle_redraw(event):
|
||||
animation.background = None
|
||||
|
||||
|
||||
# bootstrap after the first draw
|
||||
def start_anim(event):
|
||||
canvas.mpl_disconnect(start_anim.cid)
|
||||
|
||||
def local_draw():
|
||||
if animation.ax._cachedRenderer:
|
||||
animation.draw(None)
|
||||
start_anim.timer.add_callback(local_draw)
|
||||
start_anim.timer.start()
|
||||
canvas.mpl_connect('draw_event', handle_redraw)
|
||||
|
||||
|
||||
start_anim.cid = canvas.mpl_connect('draw_event', start_anim)
|
||||
start_anim.timer = animation.canvas.new_timer()
|
||||
start_anim.timer.interval = 1
|
||||
|
||||
tstart = time.time()
|
||||
|
||||
plt.show()
|
||||
print('FPS: %f' % (animation.cnt/(time.time() - tstart)))
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: pong_sgskip.py](https://matplotlib.org/_downloads/pong_sgskip.py)
|
||||
- [下载Jupyter notebook: pong_sgskip.ipynb](https://matplotlib.org/_downloads/pong_sgskip.ipynb)
|
||||
73
Python/matplotlab/gallery/event_handling/resample.md
Normal file
73
Python/matplotlab/gallery/event_handling/resample.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# 重采样数据
|
||||
|
||||
下采样会降低信号的采样率或采样大小。在本教程中,当通过拖动和缩放调整打印时,将对信号进行缩减采样。
|
||||
|
||||

|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
|
||||
# A class that will downsample the data and recompute when zoomed.
|
||||
class DataDisplayDownsampler(object):
|
||||
def __init__(self, xdata, ydata):
|
||||
self.origYData = ydata
|
||||
self.origXData = xdata
|
||||
self.max_points = 50
|
||||
self.delta = xdata[-1] - xdata[0]
|
||||
|
||||
def downsample(self, xstart, xend):
|
||||
# get the points in the view range
|
||||
mask = (self.origXData > xstart) & (self.origXData < xend)
|
||||
# dilate the mask by one to catch the points just outside
|
||||
# of the view range to not truncate the line
|
||||
mask = np.convolve([1, 1], mask, mode='same').astype(bool)
|
||||
# sort out how many points to drop
|
||||
ratio = max(np.sum(mask) // self.max_points, 1)
|
||||
|
||||
# mask data
|
||||
xdata = self.origXData[mask]
|
||||
ydata = self.origYData[mask]
|
||||
|
||||
# downsample data
|
||||
xdata = xdata[::ratio]
|
||||
ydata = ydata[::ratio]
|
||||
|
||||
print("using {} of {} visible points".format(
|
||||
len(ydata), np.sum(mask)))
|
||||
|
||||
return xdata, ydata
|
||||
|
||||
def update(self, ax):
|
||||
# Update the line
|
||||
lims = ax.viewLim
|
||||
if np.abs(lims.width - self.delta) > 1e-8:
|
||||
self.delta = lims.width
|
||||
xstart, xend = lims.intervalx
|
||||
self.line.set_data(*self.downsample(xstart, xend))
|
||||
ax.figure.canvas.draw_idle()
|
||||
|
||||
|
||||
# Create a signal
|
||||
xdata = np.linspace(16, 365, (365-16)*4)
|
||||
ydata = np.sin(2*np.pi*xdata/153) + np.cos(2*np.pi*xdata/127)
|
||||
|
||||
d = DataDisplayDownsampler(xdata, ydata)
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
|
||||
# Hook up the line
|
||||
d.line, = ax.plot(xdata, ydata, 'o-')
|
||||
ax.set_autoscale_on(False) # Otherwise, infinite loop
|
||||
|
||||
# Connect for changing the view limits
|
||||
ax.callbacks.connect('xlim_changed', d.update)
|
||||
ax.set_xlim(16, 365)
|
||||
plt.show()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: resample.py](https://matplotlib.org/_downloads/resample.py)
|
||||
- [下载Jupyter notebook: resample.ipynb](https://matplotlib.org/_downloads/resample.ipynb)
|
||||
40
Python/matplotlab/gallery/event_handling/timers.md
Normal file
40
Python/matplotlab/gallery/event_handling/timers.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# 计时器
|
||||
|
||||
使用通用计时器对象的简单示例。这用于更新图中标题的时间。
|
||||
|
||||

|
||||
|
||||
```python
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
def update_title(axes):
|
||||
axes.set_title(datetime.now())
|
||||
axes.figure.canvas.draw()
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
|
||||
x = np.linspace(-3, 3)
|
||||
ax.plot(x, x ** 2)
|
||||
|
||||
# Create a new timer object. Set the interval to 100 milliseconds
|
||||
# (1000 is default) and tell the timer what function should be called.
|
||||
timer = fig.canvas.new_timer(interval=100)
|
||||
timer.add_callback(update_title, ax)
|
||||
timer.start()
|
||||
|
||||
# Or could start the timer on first figure draw
|
||||
#def start_timer(evt):
|
||||
# timer.start()
|
||||
# fig.canvas.mpl_disconnect(drawid)
|
||||
#drawid = fig.canvas.mpl_connect('draw_event', start_timer)
|
||||
|
||||
plt.show()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: timers.py](https://matplotlib.org/_downloads/timers.py)
|
||||
- [下载Jupyter notebook: timers.ipynb](https://matplotlib.org/_downloads/timers.ipynb)
|
||||
@@ -0,0 +1,65 @@
|
||||
# Trifinder 事件演示
|
||||
|
||||
显示使用TriFinder对象的示例。当鼠标在三角测量上移动时,光标下方的三角形将突出显示,三角形的索引将显示在图表标题中。
|
||||
|
||||

|
||||
|
||||
```python
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib.tri import Triangulation
|
||||
from matplotlib.patches import Polygon
|
||||
import numpy as np
|
||||
|
||||
|
||||
def update_polygon(tri):
|
||||
if tri == -1:
|
||||
points = [0, 0, 0]
|
||||
else:
|
||||
points = triang.triangles[tri]
|
||||
xs = triang.x[points]
|
||||
ys = triang.y[points]
|
||||
polygon.set_xy(np.column_stack([xs, ys]))
|
||||
|
||||
|
||||
def motion_notify(event):
|
||||
if event.inaxes is None:
|
||||
tri = -1
|
||||
else:
|
||||
tri = trifinder(event.xdata, event.ydata)
|
||||
update_polygon(tri)
|
||||
plt.title('In triangle %i' % tri)
|
||||
event.canvas.draw()
|
||||
|
||||
|
||||
# Create a Triangulation.
|
||||
n_angles = 16
|
||||
n_radii = 5
|
||||
min_radius = 0.25
|
||||
radii = np.linspace(min_radius, 0.95, n_radii)
|
||||
angles = np.linspace(0, 2 * np.pi, n_angles, endpoint=False)
|
||||
angles = np.repeat(angles[..., np.newaxis], n_radii, axis=1)
|
||||
angles[:, 1::2] += np.pi / n_angles
|
||||
x = (radii*np.cos(angles)).flatten()
|
||||
y = (radii*np.sin(angles)).flatten()
|
||||
triang = Triangulation(x, y)
|
||||
triang.set_mask(np.hypot(x[triang.triangles].mean(axis=1),
|
||||
y[triang.triangles].mean(axis=1))
|
||||
< min_radius)
|
||||
|
||||
# Use the triangulation's default TriFinder object.
|
||||
trifinder = triang.get_trifinder()
|
||||
|
||||
# Setup plot and callbacks.
|
||||
plt.subplot(111, aspect='equal')
|
||||
plt.triplot(triang, 'bo-')
|
||||
polygon = Polygon([[0, 0], [0, 0]], facecolor='y') # dummy data for xs,ys
|
||||
update_polygon(-1)
|
||||
plt.gca().add_patch(polygon)
|
||||
plt.gcf().canvas.mpl_connect('motion_notify_event', motion_notify)
|
||||
plt.show()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: trifinder_event_demo.py](https://matplotlib.org/_downloads/trifinder_event_demo.py)
|
||||
- [下载Jupyter notebook: trifinder_event_demo.ipynb](https://matplotlib.org/_downloads/trifinder_event_demo.ipynb)
|
||||
90
Python/matplotlab/gallery/event_handling/viewlims.md
Normal file
90
Python/matplotlab/gallery/event_handling/viewlims.md
Normal file
@@ -0,0 +1,90 @@
|
||||
# Viewlims
|
||||
|
||||
创建两个相同的面板。在右侧面板上放大将在第一个面板中显示一个矩形,表示缩放的区域。
|
||||
|
||||

|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib.patches import Rectangle
|
||||
|
||||
|
||||
# We just subclass Rectangle so that it can be called with an Axes
|
||||
# instance, causing the rectangle to update its shape to match the
|
||||
# bounds of the Axes
|
||||
class UpdatingRect(Rectangle):
|
||||
def __call__(self, ax):
|
||||
self.set_bounds(*ax.viewLim.bounds)
|
||||
ax.figure.canvas.draw_idle()
|
||||
|
||||
|
||||
# A class that will regenerate a fractal set as we zoom in, so that you
|
||||
# can actually see the increasing detail. A box in the left panel will show
|
||||
# the area to which we are zoomed.
|
||||
class MandelbrotDisplay(object):
|
||||
def __init__(self, h=500, w=500, niter=50, radius=2., power=2):
|
||||
self.height = h
|
||||
self.width = w
|
||||
self.niter = niter
|
||||
self.radius = radius
|
||||
self.power = power
|
||||
|
||||
def __call__(self, xstart, xend, ystart, yend):
|
||||
self.x = np.linspace(xstart, xend, self.width)
|
||||
self.y = np.linspace(ystart, yend, self.height).reshape(-1, 1)
|
||||
c = self.x + 1.0j * self.y
|
||||
threshold_time = np.zeros((self.height, self.width))
|
||||
z = np.zeros(threshold_time.shape, dtype=complex)
|
||||
mask = np.ones(threshold_time.shape, dtype=bool)
|
||||
for i in range(self.niter):
|
||||
z[mask] = z[mask]**self.power + c[mask]
|
||||
mask = (np.abs(z) < self.radius)
|
||||
threshold_time += mask
|
||||
return threshold_time
|
||||
|
||||
def ax_update(self, ax):
|
||||
ax.set_autoscale_on(False) # Otherwise, infinite loop
|
||||
|
||||
# Get the number of points from the number of pixels in the window
|
||||
dims = ax.patch.get_window_extent().bounds
|
||||
self.width = int(dims[2] + 0.5)
|
||||
self.height = int(dims[2] + 0.5)
|
||||
|
||||
# Get the range for the new area
|
||||
xstart, ystart, xdelta, ydelta = ax.viewLim.bounds
|
||||
xend = xstart + xdelta
|
||||
yend = ystart + ydelta
|
||||
|
||||
# Update the image object with our new data and extent
|
||||
im = ax.images[-1]
|
||||
im.set_data(self.__call__(xstart, xend, ystart, yend))
|
||||
im.set_extent((xstart, xend, ystart, yend))
|
||||
ax.figure.canvas.draw_idle()
|
||||
|
||||
md = MandelbrotDisplay()
|
||||
Z = md(-2., 0.5, -1.25, 1.25)
|
||||
|
||||
fig1, (ax1, ax2) = plt.subplots(1, 2)
|
||||
ax1.imshow(Z, origin='lower', extent=(md.x.min(), md.x.max(), md.y.min(), md.y.max()))
|
||||
ax2.imshow(Z, origin='lower', extent=(md.x.min(), md.x.max(), md.y.min(), md.y.max()))
|
||||
|
||||
rect = UpdatingRect([0, 0], 0, 0, facecolor='None', edgecolor='black', linewidth=1.0)
|
||||
rect.set_bounds(*ax2.viewLim.bounds)
|
||||
ax1.add_patch(rect)
|
||||
|
||||
# Connect for changing the view limits
|
||||
ax2.callbacks.connect('xlim_changed', rect)
|
||||
ax2.callbacks.connect('ylim_changed', rect)
|
||||
|
||||
ax2.callbacks.connect('xlim_changed', md.ax_update)
|
||||
ax2.callbacks.connect('ylim_changed', md.ax_update)
|
||||
ax2.set_title("Zoom here")
|
||||
|
||||
plt.show()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: viewlims.py](https://matplotlib.org/_downloads/viewlims.py)
|
||||
- [下载Jupyter notebook: viewlims.ipynb](https://matplotlib.org/_downloads/viewlims.ipynb)
|
||||
44
Python/matplotlab/gallery/event_handling/zoom_window.md
Normal file
44
Python/matplotlab/gallery/event_handling/zoom_window.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# 缩放窗口
|
||||
|
||||
此示例显示如何将一个窗口(例如鼠标按键)中的事件连接到另一个体形窗口。
|
||||
|
||||
如果单击第一个窗口中的某个点,将调整第二个窗口的z和y限制,以便第二个窗口中缩放的中心将是所单击点的x,y坐标。
|
||||
|
||||
请注意,散点图中圆的直径以点**2定义,因此它们的大小与缩放无关。
|
||||
|
||||

|
||||
|
||||
```python
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
figsrc, axsrc = plt.subplots()
|
||||
figzoom, axzoom = plt.subplots()
|
||||
axsrc.set(xlim=(0, 1), ylim=(0, 1), autoscale_on=False,
|
||||
title='Click to zoom')
|
||||
axzoom.set(xlim=(0.45, 0.55), ylim=(0.4, 0.6), autoscale_on=False,
|
||||
title='Zoom window')
|
||||
|
||||
x, y, s, c = np.random.rand(4, 200)
|
||||
s *= 200
|
||||
|
||||
axsrc.scatter(x, y, s, c)
|
||||
axzoom.scatter(x, y, s, c)
|
||||
|
||||
|
||||
def onpress(event):
|
||||
if event.button != 1:
|
||||
return
|
||||
x, y = event.xdata, event.ydata
|
||||
axzoom.set_xlim(x - 0.1, x + 0.1)
|
||||
axzoom.set_ylim(y - 0.1, y + 0.1)
|
||||
figzoom.canvas.draw()
|
||||
|
||||
figsrc.canvas.mpl_connect('button_press_event', onpress)
|
||||
plt.show()
|
||||
```
|
||||
|
||||
## 下载这个示例
|
||||
|
||||
- [下载python源码: zoom_window.py](https://matplotlib.org/_downloads/zoom_window.py)
|
||||
- [下载Jupyter notebook: zoom_window.ipynb](https://matplotlib.org/_downloads/zoom_window.ipynb)
|
||||
Reference in New Issue
Block a user