<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                # 事件處理及拾取 > 原文:[Event handling and picking](http://matplotlib.org/users/event_handling.html) > 譯者:[飛龍](https://github.com/) > 協議:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) matplotlib 使用了許多用戶界面工具包(wxpython,tkinter,qt4,gtk 和 macosx),為了支持交互式平移和縮放圖形等功能,擁有一套 API 通過按鍵和鼠標移動與圖形交互,并且『GUI中立』,對開發人員十分有幫助,所以我們不必重復大量的代碼來跨不同的用戶界面。雖然事件處理 API 是 GUI 中立的,但它是基于 GTK 模型,這是 matplotlib 支持的第一個用戶界面。與標準 GUI 事件相比,被觸發的事件也比 matplotlib 豐富一些,例如包括發生事件的`matplotlib.axes.Axes`的信息。事件還能夠理解 matplotlib 坐標系,并且在事件中以像素和數據坐標為單位報告事件位置。 ## 事件連接 要接收事件,你需要編寫一個回調函數,然后將你的函數連接到事件管理器,它是`FigureCanvasBase`的一部分。這是一個簡單的例子,打印鼠標點擊的位置和按下哪個按鈕: ```py fig = plt.figure() ax = fig.add_subplot(111) ax.plot(np.random.rand(10)) def onclick(event): print('button=%d, x=%d, y=%d, xdata=%f, ydata=%f' % (event.button, event.x, event.y, event.xdata, event.ydata)) cid = fig.canvas.mpl_connect('button_press_event', onclick) ``` `FigureCanvas`的方法`mpl_connect()`返回一個連接`id`,它只是一個整數。 當你要斷開回調時,只需調用: ```py fig.canvas.mpl_disconnect(cid) ``` > 注意 > 畫布僅保留回調的弱引用。 因此,如果回調是類實例的方法,你需要保留對該實例的引用。 否則實例將被垃圾回收,回調將消失。 以下是可以連接到的事件,在事件發生時發回給你的類實例以及事件描述: | 事件名稱 | 類和描述 | | --- | --- | --- | | `'button_press_event'` | `MouseEvent` - 鼠標按鈕被按下 | | `'button_release_event'` | `MouseEvent` - 鼠標按鈕被釋放 | | `'draw_event'` | `DrawEvent` - 畫布繪圖 | | `'key_press_event'` | `KeyEvent` - 按鍵被按下 | | `'key_release_event'` | `KeyEvent` - 按鍵被釋放 | | `'motion_notify_event'` | `MouseEvent` - 鼠標移動 | | `'pick_event'` | `PickEvent` - 畫布中的對象被選中 | | `'resize_event'` | `ResizeEvent` - 圖形畫布大小改變 | | `'scroll_event'` | `MouseEvent` - 鼠標滾輪被滾動 | | `'figure_enter_event'` | `LocationEvent` - 鼠標進入新的圖形 | | `'figure_leave_event'` | `LocationEvent` - 鼠標離開圖形 | | `'axes_enter_event'` | `LocationEvent` - 鼠標進入新的軸域 | | `'axes_leave_event'` | `LocationEvent` - 鼠標離開軸域 | ## 事件屬性 所有 matplotlib 事件繼承自基類`matplotlib.backend_bases.Event`,儲存以下屬性: `name` 事件名稱 `canvas` 生成事件的`FigureCanvas `實例 `guiEvent` 觸發 matplotlib 事件的 GUI 事件 最常見的事件是按鍵按下/釋放事件、鼠標按下/釋放和移動事件。 處理這些事件的`KeyEvent`和`MouseEvent`類都派生自`LocationEvent`,它具有以下屬性: `x` x 位置,距離畫布左端的像素 `y` y 位置,距離畫布底端的像素 `inaxes` 如果鼠標經過軸域,則為`Axes`實例 `xdata` 鼠標的`x`坐標,以數據坐標為單位 `ydata` 鼠標的`y`坐標,以數據坐標為單位 但我們看一看畫布的簡單示例,其中每次按下鼠標時都會創建一條線段。 ```py from matplotlib import pyplot as plt class LineBuilder: def __init__(self, line): self.line = line self.xs = list(line.get_xdata()) self.ys = list(line.get_ydata()) self.cid = line.figure.canvas.mpl_connect('button_press_event', self) def __call__(self, event): print('click', event) if event.inaxes!=self.line.axes: return self.xs.append(event.xdata) self.ys.append(event.ydata) self.line.set_data(self.xs, self.ys) self.line.figure.canvas.draw() fig = plt.figure() ax = fig.add_subplot(111) ax.set_title('click to build line segments') line, = ax.plot([0], [0]) # empty line linebuilder = LineBuilder(line) plt.show() ``` 我們剛剛使用的`MouseEvent`是一個`LocationEvent`,因此我們可以訪問`event.x`和`event.xdata`中的數據和像素坐標。 除了`LocationEvent`屬性,它擁有: `button` 按下的按鈕,`None`、1、2、3、`'up'`、`'down'`(`'up'`、`'down'`用于滾動事件) `key` 按下的鍵,`None`,任何字符,`'shift'`、`'win'`或者`'control'` ### 可拖拽的矩形練習 編寫使用`Rectangle`實例初始化的可拖動矩形類,但在拖動時會移動其`x`,`y`位置。 提示:你需要存儲矩形的原始`xy`位置,存儲為`rect.xy`并連接到按下,移動和釋放鼠標事件。 當鼠標按下時,檢查點擊是否發生在你的矩形上(見`matplotlib.patches.Rectangle.contains()`),如果是,存儲矩形`xy`和數據坐標為單位的鼠標點擊位置。 在移動事件回調中,計算鼠標移動的`deltax`和`deltay`,并將這些增量添加到存儲的原始矩形,并重新繪圖。 在按鈕釋放事件中,只需將所有你存儲的按鈕按下數據重置為`None`。 這里是解決方案: ```py import numpy as np import matplotlib.pyplot as plt class DraggableRectangle: def __init__(self, rect): self.rect = rect self.press = None def connect(self): 'connect to all the events we need' self.cidpress = self.rect.figure.canvas.mpl_connect( 'button_press_event', self.on_press) self.cidrelease = self.rect.figure.canvas.mpl_connect( 'button_release_event', self.on_release) self.cidmotion = self.rect.figure.canvas.mpl_connect( 'motion_notify_event', self.on_motion) def on_press(self, event): 'on button press we will see if the mouse is over us and store some data' if event.inaxes != self.rect.axes: return contains, attrd = self.rect.contains(event) if not contains: return print('event contains', self.rect.xy) x0, y0 = self.rect.xy self.press = x0, y0, event.xdata, event.ydata def on_motion(self, event): 'on motion we will move the rect if the mouse is over us' if self.press is None: return if event.inaxes != self.rect.axes: return x0, y0, xpress, ypress = self.press dx = event.xdata - xpress dy = event.ydata - ypress #print('x0=%f, xpress=%f, event.xdata=%f, dx=%f, x0+dx=%f' % # (x0, xpress, event.xdata, dx, x0+dx)) self.rect.set_x(x0+dx) self.rect.set_y(y0+dy) self.rect.figure.canvas.draw() def on_release(self, event): 'on release we reset the press data' self.press = None self.rect.figure.canvas.draw() def disconnect(self): 'disconnect all the stored connection ids' self.rect.figure.canvas.mpl_disconnect(self.cidpress) self.rect.figure.canvas.mpl_disconnect(self.cidrelease) self.rect.figure.canvas.mpl_disconnect(self.cidmotion) fig = plt.figure() ax = fig.add_subplot(111) rects = ax.bar(range(10), 20*np.random.rand(10)) drs = [] for rect in rects: dr = DraggableRectangle(rect) dr.connect() drs.append(dr) plt.show() ``` 附加題:使用動畫秘籍中討論的動畫 blit 技術,使動畫繪制更快更流暢。 附加題解決方案: ```py # draggable rectangle with the animation blit techniques; see # http://www.scipy.org/Cookbook/Matplotlib/Animations import numpy as np import matplotlib.pyplot as plt class DraggableRectangle: lock = None # only one can be animated at a time def __init__(self, rect): self.rect = rect self.press = None self.background = None def connect(self): 'connect to all the events we need' self.cidpress = self.rect.figure.canvas.mpl_connect( 'button_press_event', self.on_press) self.cidrelease = self.rect.figure.canvas.mpl_connect( 'button_release_event', self.on_release) self.cidmotion = self.rect.figure.canvas.mpl_connect( 'motion_notify_event', self.on_motion) def on_press(self, event): 'on button press we will see if the mouse is over us and store some data' if event.inaxes != self.rect.axes: return if DraggableRectangle.lock is not None: return contains, attrd = self.rect.contains(event) if not contains: return print('event contains', self.rect.xy) x0, y0 = self.rect.xy self.press = x0, y0, event.xdata, event.ydata DraggableRectangle.lock = self # draw everything but the selected rectangle and store the pixel buffer canvas = self.rect.figure.canvas axes = self.rect.axes self.rect.set_animated(True) canvas.draw() self.background = canvas.copy_from_bbox(self.rect.axes.bbox) # now redraw just the rectangle axes.draw_artist(self.rect) # and blit just the redrawn area canvas.blit(axes.bbox) def on_motion(self, event): 'on motion we will move the rect if the mouse is over us' if DraggableRectangle.lock is not self: return if event.inaxes != self.rect.axes: return x0, y0, xpress, ypress = self.press dx = event.xdata - xpress dy = event.ydata - ypress self.rect.set_x(x0+dx) self.rect.set_y(y0+dy) canvas = self.rect.figure.canvas axes = self.rect.axes # restore the background region canvas.restore_region(self.background) # redraw just the current rectangle axes.draw_artist(self.rect) # blit just the redrawn area canvas.blit(axes.bbox) def on_release(self, event): 'on release we reset the press data' if DraggableRectangle.lock is not self: return self.press = None DraggableRectangle.lock = None # turn off the rect animation property and reset the background self.rect.set_animated(False) self.background = None # redraw the full figure self.rect.figure.canvas.draw() def disconnect(self): 'disconnect all the stored connection ids' self.rect.figure.canvas.mpl_disconnect(self.cidpress) self.rect.figure.canvas.mpl_disconnect(self.cidrelease) self.rect.figure.canvas.mpl_disconnect(self.cidmotion) fig = plt.figure() ax = fig.add_subplot(111) rects = ax.bar(range(10), 20*np.random.rand(10)) drs = [] for rect in rects: dr = DraggableRectangle(rect) dr.connect() drs.append(dr) plt.show() ``` ## 鼠標進入和離開 如果希望在鼠標進入或離開圖形時通知你,你可以連接到圖形/軸域進入/離開事件。 下面是一個簡單的例子,它改變了鼠標所在的軸域和圖形的背景顏色: ```py """ Illustrate the figure and axes enter and leave events by changing the frame colors on enter and leave """ 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() fig1 = plt.figure() fig1.suptitle('mouse hover over figure or axes to trigger events') ax1 = fig1.add_subplot(211) ax2 = fig1.add_subplot(212) 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) fig2 = plt.figure() fig2.suptitle('mouse hover over figure or axes to trigger events') ax1 = fig2.add_subplot(211) ax2 = fig2.add_subplot(212) 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() ``` ## 對象拾取 你可以通過設置藝術家的`picker `屬性(例如,matplotlib `Line2D`,`Text`,`Patch`,`Polygon`,`AxesImage`等)來啟用選擇, `picker `屬性有多種含義: `None` 選擇對于該藝術家已禁用(默認) `boolean` 如果為`True`,則啟用選擇,當鼠標移動到該藝術家上方時,會觸發事件 `float` 如果選擇器是數字,則將其解釋為點的 ε 公差,并且如果其數據在鼠標事件的 ε 內,則藝術家將觸發事件。 對于像線條和補丁集合的一些藝術家,藝術家可以向生成的選擇事件提供附加數據,例如,在選擇事件的 ε 內的數據的索引。 函數 如果拾取器是可調用的,則它是用戶提供的函數,用于確定藝術家是否被鼠標事件擊中。 簽名為`hit, props = picker(artist, mouseevent)`,用于測試是否命中。 如果鼠標事件在藝術家上,返回`hit = True`,`props`是一個屬性字典,它們會添加到`PickEvent`屬性。 通過設置`picker`屬性啟用對藝術家進行拾取后,你需要連接到圖畫布的`pick_event`,以便在鼠標按下事件中獲取拾取回調。 例如: ```py def pick_handler(event): mouseevent = event.mouseevent artist = event.artist # now do something with this... ``` 傳給你的回調的`PickEvent`事件永遠有兩個屬性: `mouseevent ` 是生成拾取事件的鼠標事件。鼠標事件具有像`x`和`y`(顯示空間中的坐標,例如,距離左,下的像素)和`xdata`,`ydata`(數據空間中的坐標)的屬性。 此外,你可以獲取有關按下哪些按鈕,按下哪些鍵,鼠標在哪個軸域上面等信息。詳細信息請參閱`matplotlib.backend_bases.MouseEvent`。 `artist` 生成拾取事件的`Artist`。 另外,像`Line2D`和`PatchCollection`的某些藝術家可以將附加的元數據(如索引)附加到滿足選擇器標準的數據中(例如,行中在指定 ε 容差內的所有點) ### 簡單拾取示例 在下面的示例中,我們將行選擇器屬性設置為標量,因此它表示以點為單位的容差(72 點/英寸)。 當拾取事件位于距離線條的容差范圍時,將調用`onpick`回調函數,并且帶有在拾取距離容差內的數據頂點索引。 我們的`onpick`回調函數只打印在拾取位置上的數據。 不同的 matplotlib 藝術家可以將不同的數據附加到`PickEvent`。 例如,`Line2D`將`ind`屬性作為索引附加到拾取點下面的行數據中。 有關`Line`的`PickEvent`屬性的詳細信息,請參閱`pick()`。 這里是代碼: ```py import numpy as np import matplotlib.pyplot as plt fig = plt.figure() ax = fig.add_subplot(111) ax.set_title('click on points') line, = ax.plot(np.random.rand(100), 'o', picker=5) # 5 points tolerance def onpick(event): thisline = event.artist xdata = thisline.get_xdata() ydata = thisline.get_ydata() ind = event.ind points = tuple(zip(xdata[ind], ydata[ind])) print('onpick points:', points) fig.canvas.mpl_connect('pick_event', onpick) plt.show() ``` ### 拾取練習 創建含有 100 個數組的數據集,包含 1000 個高斯隨機數,并計算每個數組的樣本平均值和標準差(提示:`numpy`數組具有`mean`和`std`方法),并制作 100 個均值與 100 個標準的`xy`標記圖。 將繪圖命令創建的線條連接到拾取事件,并繪制數據的原始時間序列,這些數據生成了被點擊的點。 如果在被點擊的點的容差范圍內存在多于一個點,則可以使用多個子圖來繪制多個時間序列。 練習的解決方案: ```py """ compute the mean and stddev of 100 data sets and plot mean vs stddev. When you click on one of the mu, sigma points, plot the raw data from the dataset that generated the mean and stddev """ 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 = plt.figure() ax = fig.add_subplot(111) 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 = plt.figure() for subplotnum, dataind in enumerate(event.ind): ax = figi.add_subplot(N,1,subplotnum+1) ax.plot(X[dataind]) ax.text(0.05, 0.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() ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看