[英]Getting coordinates of the closest data point on matplotlib plot
我將matplotlib
與NavigationToolbar2QT
。 工具欄顯示光標的位置。 但我希望光標捕捉到最近的數據點(當足夠接近時)或者只是顯示最近數據點的坐標。 可以以某種方式安排嗎?
如果您正在處理大量點,我建議您使用CKDtrees
:
import matplotlib.pyplot as plt
import numpy as np
import scipy.spatial
points = np.column_stack([np.random.rand(50), np.random.rand(50)])
fig, ax = plt.subplots()
coll = ax.scatter(points[:,0], points[:,1])
ckdtree = scipy.spatial.cKDTree(points)
我在這里重構了kpie's
答案。 創建ckdtree
,您可以立即識別最近的點以及有關它們的各種信息,只需稍加努力:
def closest_point_distance(ckdtree, x, y):
#returns distance to closest point
return ckdtree.query([x, y])[0]
def closest_point_id(ckdtree, x, y):
#returns index of closest point
return ckdtree.query([x, y])[1]
def closest_point_coords(ckdtree, x, y):
# returns coordinates of closest point
return ckdtree.data[closest_point_id(ckdtree, x, y)]
# ckdtree.data is the same as points
光標位置的交互式顯示。 如果您希望在導航工具欄上顯示最近點的坐標:
def val_shower(ckdtree):
#formatter of coordinates displayed on Navigation Bar
return lambda x, y: '[x = {}, y = {}]'.format(*closest_point_coords(ckdtree, x, y))
plt.gca().format_coord = val_shower(ckdtree)
plt.show()
使用事件。 如果你想要另一種交互性,你可以使用事件:
def onclick(event):
if event.inaxes is not None:
print(closest_point_coords(ckdtree, event.xdata, event.ydata))
fig.canvas.mpl_connect('motion_notify_event', onclick)
plt.show()
您可以mouse_move
NavigationToolbar2QT
並覆蓋mouse_move
處理程序。 xdata
和ydata
屬性包含繪圖坐標中的當前鼠標位置。 在將事件傳遞給基類mouse_move
處理程序之前,您可以將其捕捉到最近的數據點。
完整示例,突出顯示圖中最近的點作為獎勵:
import sys
import numpy as np
from matplotlib.backends.qt_compat import QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvas, NavigationToolbar2QT
from matplotlib.figure import Figure
class Snapper:
"""Snaps to data points"""
def __init__(self, data, callback):
self.data = data
self.callback = callback
def snap(self, x, y):
pos = np.array([x, y])
distances = np.linalg.norm(self.data - pos, axis=1)
dataidx = np.argmin(distances)
datapos = self.data[dataidx,:]
self.callback(datapos[0], datapos[1])
return datapos
class SnappingNavigationToolbar(NavigationToolbar2QT):
"""Navigation toolbar with data snapping"""
def __init__(self, canvas, parent, coordinates=True):
super().__init__(canvas, parent, coordinates)
self.snapper = None
def set_snapper(self, snapper):
self.snapper = snapper
def mouse_move(self, event):
if self.snapper and event.xdata and event.ydata:
event.xdata, event.ydata = self.snapper.snap(event.xdata, event.ydata)
super().mouse_move(event)
class Highlighter:
def __init__(self, ax):
self.ax = ax
self.marker = None
self.markerpos = None
def draw(self, x, y):
"""draws a marker at plot position (x,y)"""
if (x, y) != self.markerpos:
if self.marker:
self.marker.remove()
del self.marker
self.marker = self.ax.scatter(x, y, color='yellow')
self.markerpos = (x, y)
self.ax.figure.canvas.draw()
class ApplicationWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self._main = QtWidgets.QWidget()
self.setCentralWidget(self._main)
layout = QtWidgets.QVBoxLayout(self._main)
canvas = FigureCanvas(Figure(figsize=(5,3)))
layout.addWidget(canvas)
toolbar = SnappingNavigationToolbar(canvas, self)
self.addToolBar(toolbar)
data = np.random.randn(100, 2)
ax = canvas.figure.subplots()
ax.scatter(data[:,0], data[:,1])
self.highlighter = Highlighter(ax)
snapper = Snapper(data, self.highlighter.draw)
toolbar.set_snapper(snapper)
if __name__ == "__main__":
qapp = QtWidgets.QApplication(sys.argv)
app = ApplicationWindow()
app.show()
qapp.exec_()
以下代碼將在您單擊時打印最靠近鼠標的點的坐標。
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(19680801)
N = 50
x = np.random.rand(N)
y = np.random.rand(N)
fig,ax = plt.subplots()
plt.scatter(x, y)
points = list(zip(x,y))
def distance(a,b):
return(sum([(k[0]-k[1])**2 for k in zip(a,b)])**0.5)
def onclick(event):
dists = [distance([event.xdata, event.ydata],k) for k in points]
print(points[dists.index(min(dists))])
fig.canvas.mpl_connect('button_press_event', onclick)
plt.show()
另一種可能性是使用已有的采摘支撐軸。 請參閱事件處理文檔中的這一部分。
吉姆
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.