如何在matplotlib中将文本框附加到鼠标光标?

时间:2019-04-29 22:37:04

标签: python matplotlib animation

我在matplotlib图中显示了一条数据曲线。我想在鼠标光标上附加一个文本框。即,当鼠标光标在图中移动时,文本框也随之移动。另外,我希望能够随着带有附加文本框的光标移动来更新文本框中的文本。

我从https://matplotlib.org/gallery/misc/cursor_demo_sgskip.html的matplotlib示例开始,但出于我的目的对其进行了修改却没有成功。我还查看了一些第三方软件包(例如mpldatacursor和mplcursors);但是,这些似乎不适合我的应用。

以下是我正在尝试的一些代码,这些代码应该可以说明我要完成的工作。

# -*- coding: iso-8859-1 -*-#
#!/usr/bin/env python
# The following allows special characters to be in comments (e.g. the extended Swedish alphabet)
# coding:utf-8
import matplotlib.pyplot as plt
# For setting size and position of matplotlib figure 
import matplotlib
matplotlib.use("WXAgg")
import numpy as np

class Cursor(object):
    """
     Purpose: Define a cursor whose interesection will track points along a curve
    """
    def __init__(self, ax):
        self.ax = ax
        self.lx = ax.axhline(color='k',linewidth=0.25)  # the horiz line
        self.ly = ax.axvline(color='k',linewidth=0.25)  # the vert line

        # Text location in axes coords
        self.txt = ax.text(0.7, 0.9, '', transform=ax.transAxes)

    def mouse_move(self, event):
        '''
         Purpose: respond to movement of the mouse
        '''
        if not event.inaxes: return
        x, y = event.xdata, event.ydata
        props = dict(boxstyle='round', facecolor='wheat', alpha=0.4)
        self.ax.text(x, y, 'test',  fontsize=8, bbox=props) 
        #self.ax.text(x,y,'')   
        #self.text(x, y, 'test',  fontsize=8, bbox=props)   
        #ax.text(x, y, 'test',  fontsize=8, bbox=props)   
        # Update the line positions
        self.lx.set_ydata(y)
        self.ly.set_xdata(x)

        self.txt.set_text('x=%1.2f, y=%1.2f' % (x, y))
        self.ax.text(x,y,'')   
        plt.draw()

class SnaptoCursor(object):
    """
    Like Cursor but the current center of the crosshair at (x,y) will snap to the nearest
    (x,y) on the curve.
    For simplicity, I'm assuming x is sorted
    """
    def __init__(self, ax, x, y):
        self.ax  = ax
        self.lx  = ax.axhline(color='k')  # the horiz line
        self.ly  = ax.axvline(color='k')  # the vert line
        self.x   = x
        self.y   = y
        # Text location in axes coords

        self.txt = ax.text(0.7, 0.9, '', transform=ax.transAxes)


    def mouse_move(self, event):
        """
         Purpose: Track the movement of the mouse coords and then update the position
                  of the intersection of the cursor cross-hairs
        """
        if not event.inaxes:            
            return
        x, y = event.xdata, event.ydata       # x,y coordinates of mouse

        props = dict(boxstyle='round', facecolor='wheat', alpha=0.4)
        self.ax.text(x, y, 'test',  fontsize=8, bbox=props)            
        #self.text(x, y, 'test',  fontsize=8, bbox=props)   
        #ax.text(x, y, 'test',  fontsize=8, bbox=props)           
        #self.ax.text(remove)   

        # Find closest pt on data curve to (x,y) of cross-air intersection
        indx = min(np.searchsorted(self.x, [x])[0], len(self.x) - 1)
        x = self.x[indx]
        y = self.y[indx]
        # Update the line positions
        self.lx.set_ydata(y)
        self.ly.set_xdata(x)
        # place a text box in upper left in axes coords
        #self.ax.text(x, y, 'test', transform=ax.transAxes, fontsize=8,
        #        verticalalignment='top', bbox=props)        

        self.txt.set_text('x=%1.2f, y=%1.2f' % (x, y))
        print('x=%1.2f, y=%1.2f' % (x, y))
        plt.draw()

t = np.arange(0.0, 1.0, 0.01)
s = np.sin(2 * 2 * np.pi * t)
fig, ax = plt.subplots(figsize=(14,7.5))
fig.canvas.set_window_title('TS with tracking cursor')
# Need the following to set position the plot
pltManager = plt.get_current_fig_manager()
pltManager.window.SetPosition((20,20))  # pixels offset from top left corner of display   

# cursor = Cursor(ax)
cursor = SnaptoCursor(ax, t, s)
plt.connect('motion_notify_event', cursor.mouse_move)

ax.plot (t, s, 'o')   

plt.axis([0, 1, -1, 1])
plt.grid(axis='both')
plt.show()

该文本框确实会用鼠标光标“粘住”,但在移动光标时不会删除它---这是需要解决的问题。向正确方向迈出的一小步

# -*- coding: iso-8859-1 -*-#
#!/usr/bin/env python
# The following allows special characters to be in comments (e.g. the extended Swedish alphabet)
# coding:utf-8
import matplotlib.pyplot as plt
# For setting size and position of matplotlib figure 
import matplotlib
matplotlib.use("WXAgg")
import numpy as np


class SnaptoCursor(object):
    """
    Like Cursor but the current center of the crosshair at (x,y) will snap to the nearest
    (x,y) on the curve.
    For simplicity, I'm assuming x is sorted
    """
    def __init__(self, ax, x, y):
        self.ax  = ax
        self.lx  = ax.axhline(color='k')  # the horiz line
        self.ly  = ax.axvline(color='k')  # the vert line

        self.tx  = ax.text(0.0,0.0,'test')        # the text to follow cursor

        self.x   = x
        self.y   = y
        # Text location in axes coords
        self.txt = ax.text(0.7, 0.9, '', transform=ax.transAxes)


    def mouse_move(self, event):
        """
         Purpose: Track the movement of the mouse coords and then update the position
                  of the intersection of the cursor cross-hairs
        """
        if not event.inaxes:            
            return
        x, y = event.xdata, event.ydata       # x,y coordinates of mouse
        self.tx.set_position((x,y))

        # Find closest pt on data curve to (x,y) of cross-air intersection
        indx = min(np.searchsorted(self.x, [x])[0], len(self.x) - 1)
        x = self.x[indx]
        y = self.y[indx]
        # Update the line positions
        self.lx.set_ydata(y)
        self.ly.set_xdata(x)

        self.txt.set_text('x=%1.2f, y=%1.2f' % (x, y))
        print('x=%1.2f, y=%1.2f' % (x, y))
        plt.draw()

t = np.arange(0.0, 1.0, 0.01)
s = np.sin(2 * 2 * np.pi * t)
fig, ax = plt.subplots(figsize=(14,7.5))
fig.canvas.set_window_title('TS with tracking cursor')
# Need the following to set position the plot
pltManager = plt.get_current_fig_manager()
pltManager.window.SetPosition((20,20))  # pixels offset from top left corner of display   

cursor = SnaptoCursor(ax, t, s)
plt.connect('motion_notify_event', cursor.mouse_move)

ax.plot (t, s, 'o')   

plt.axis([0, 1, -1, 1])
plt.grid(axis='both')
plt.show()

此代码将使用光标移动文本并擦除先前的文本。但是,随着光标的移动,我仍然无法更改文本!任何建议,将不胜感激:-)

2 个答案:

答案 0 :(得分:0)

您每次移动鼠标时都在创建一个新的Text对象。您需要在__init__期间创建对象,然后在移动鼠标时简单地更新其位置/文本:

# -*- coding: iso-8859-1 -*-#
#!/usr/bin/env python
# The following allows special characters to be in comments (e.g. the extended Swedish alphabet)
# coding:utf-8
import matplotlib.pyplot as plt
# For setting size and position of matplotlib figure 
import matplotlib
matplotlib.use("WXAgg")
import numpy as np

class Cursor(object):
    """
     Purpose: Define a cursor whose interesection will track points along a curve
    """
    def __init__(self, ax):
        self.ax = ax
        self.lx = ax.axhline(color='k',linewidth=0.25)  # the horiz line
        self.ly = ax.axvline(color='k',linewidth=0.25)  # the vert line

        # Text location in data coords
        props = dict(boxstyle='round', facecolor='wheat', alpha=0.4)
        self.txt = self.ax.text(0, 0, '', fontsize=8, bbox=props)

    def mouse_move(self, event):
        '''
         Purpose: respond to movement of the mouse
        '''
        if not event.inaxes: return
        x, y = event.xdata, event.ydata
        self.txt.set_position((x,y))
        # Update the line positions
        self.lx.set_ydata(y)
        self.ly.set_xdata(x)

        self.txt.set_text('x=%1.2f, y=%1.2f' % (x, y))
        plt.draw()

class SnaptoCursor(object):
    """
    Like Cursor but the current center of the crosshair at (x,y) will snap to the nearest
    (x,y) on the curve.
    For simplicity, I'm assuming x is sorted
    """
    def __init__(self, ax, x, y):
        self.ax  = ax
        self.lx  = ax.axhline(color='k')  # the horiz line
        self.ly  = ax.axvline(color='k')  # the vert line
        self.x   = x
        self.y   = y

        # Text location in data coords
        props = dict(boxstyle='round', facecolor='wheat', alpha=0.4)
        self.txt = self.ax.text(0, 0, '', fontsize=8, bbox=props)


    def mouse_move(self, event):
        """
         Purpose: Track the movement of the mouse coords and then update the position
                  of the intersection of the cursor cross-hairs
        """
        if not event.inaxes:            
            return
        x, y = event.xdata, event.ydata       # x,y coordinates of mouse

        self.txt.set_position((x,y))

        # Find closest pt on data curve to (x,y) of cross-air intersection
        indx = min(np.searchsorted(self.x, [x])[0], len(self.x) - 1)
        x = self.x[indx]
        y = self.y[indx]
        # Update the line positions
        self.lx.set_ydata(y)
        self.ly.set_xdata(x)
        # place a text box in upper left in axes coords
        #self.ax.text(x, y, 'test', transform=ax.transAxes, fontsize=8,
        #        verticalalignment='top', bbox=props)        

        self.txt.set_text('x=%1.2f, y=%1.2f' % (x, y))
        print('x=%1.2f, y=%1.2f' % (x, y))
        self.ax.figure.canvas.draw_idle()

t = np.arange(0.0, 1.0, 0.01)
s = np.sin(2 * 2 * np.pi * t)
fig, ax = plt.subplots(figsize=(14,7.5))
fig.canvas.set_window_title('TS with tracking cursor')

# cursor = Cursor(ax)
cursor = SnaptoCursor(ax, t, s)
plt.connect('motion_notify_event', cursor.mouse_move)

ax.plot (t, s, 'o')   

plt.axis([0, 1, -1, 1])
plt.grid(axis='both')
plt.show()

答案 1 :(得分:0)

这里是Diziet Asahithat的代码的经过稍微编辑的版本,可以回答我的问题:

select ID, CREATION_TIME 
from my_table 
where ID = 4 and 
      CREATION_TIME between to_date('29/04/2017 12:01:00', 'DD/MM/YYYY HH:MI:SS[AM]') and to_date('29/04/2019 01:00:00', 'DD/MM/YYYY HH:MI:SS[AM]')
order by creation_time asc;

非常感谢您的努力DA:-)