我需要一个可拖动的数据标记来手动调整数据集中的一组点。 This回答和其他人使用Patch.Circle解决了这个问题。但是,在缩放绘图时,我需要标记保持相同的大小。对于圆圈,圆圈也会缩放。我没有试图找到一种动态调整圆圈的方法,因为它看起来应该有一种更简单的移动标记的方法。有人知道怎么做吗?
答案 0 :(得分:2)
下面,我介绍一个MWE,它展示了使用matplotlib和PyQt4的面向对象API的一种方法。使用鼠标中键可以拖动数据标记。策略是使用line2D艺术家绘制数据,然后通过操纵艺术家的数据并更新绘图来拖动标记。这可以大致归纳为3个步骤:
步骤1 - 单击鼠标中键时,鼠标光标的坐标(以像素为单位)与line2D艺术家的xy数据(以像素为单位)进行比较。如果光标与最近标记之间的线性距离小于给定值(此处定义为标记的大小),则该数据标记的索引将保存在类属性draggable
中。否则,draggable
设置为None
。
第2步 - 移动鼠标时,如果draggable is not None
,则将索引存储在类属性draggable
中的数据标记的坐标设置为1鼠标光标。
第3步 - 释放鼠标中键时,draggable
将重新设置为无。
注意:如果需要,还可以使用pyplot接口生成图形而不是面向对象的API。
import sys
from PyQt4 import QtGui
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
from matplotlib.backends.backend_qt4agg import FigureManagerQT
import numpy as np
class MyFigureCanvas(FigureCanvasQTAgg):
def __init__(self):
super(MyFigureCanvas, self).__init__(Figure())
# init class attributes:
self.background = None
self.draggable = None
self.msize = 6
# plot some data:
x = np.random.rand(25)
self.ax = self.figure.add_subplot(111)
self.markers, = self.ax.plot(x, marker='o', ms=self.msize)
# define event connections:
self.mpl_connect('motion_notify_event', self.on_motion)
self.mpl_connect('button_press_event', self.on_click)
self.mpl_connect('button_release_event', self.on_release)
def on_click(self, event):
if event.button == 2: # 2 is for middle mouse button
# get mouse cursor coordinates in pixels:
x = event.x
y = event.y
# get markers xy coordinate in pixels:
xydata = self.ax.transData.transform(self.markers.get_xydata())
xdata, ydata = xydata.T
# compute the linear distance between the markers and the cursor:
r = ((xdata - x)**2 + (ydata - y)**2)**0.5
if np.min(r) < self.msize:
# save figure background:
self.markers.set_visible(False)
self.draw()
self.background = self.copy_from_bbox(self.ax.bbox)
self.markers.set_visible(True)
self.ax.draw_artist(self.markers)
self.update()
# store index of draggable marker:
self.draggable = np.argmin(r)
else:
self.draggable = None
def on_motion(self, event):
if self.draggable is not None:
if event.xdata and event.ydata:
# get markers coordinate in data units:
xdata, ydata = self.markers.get_data()
# change the coordinate of the marker that is
# being dragged to the ones of the mouse cursor:
xdata[self.draggable] = event.xdata
ydata[self.draggable] = event.ydata
# update the data of the artist:
self.markers.set_xdata(xdata)
self.markers.set_ydata(ydata)
# update the plot:
self.restore_region(self.background)
self.ax.draw_artist(self.markers)
self.update()
def on_release(self, event):
self.draggable = None
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
canvas = MyFigureCanvas()
manager = FigureManagerQT(canvas, 1)
manager.show()
sys.exit(app.exec_())