通过在曲线上移动一个点来更新曲线
Posted
技术标签:
【中文标题】通过在曲线上移动一个点来更新曲线【英文标题】:Update a curve by moving a point on it 【发布时间】:2020-03-19 20:24:07 【问题描述】:我有一些嘈杂的数据,我试图用高斯拟合。问题是我必须手动完成。我的意思是我必须移动曲线上的点(见下图)。当我移动点时,我必须更新曲线,以便它自己可以移动曲线。
例如在这条曲线上,如果我移动上面的点,它会改变我的高斯的 mu,如果我移动中间的点,它会更新 sigma 参数。在这个例子中,我在我嵌入 QMainWindow 的 matplotlib 的 FigureCanvas 中绘制了两条曲线。
我在 PyQt 小部件中嵌入的 matplotlib 图形中搜索并发现无法做到这一点。因此,我已更改并尝试将 PyQtGraph 与 ROI 工具一起使用,但效果不佳。
你知道我怎么能做到这一点吗?有没有一个简单的python库可以做到这一点?谢谢
编辑: 这是我用来生成图像的代码:
from PySide2 import QtCore, QtGui, QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import numpy as np
class PainterCanvas(FigureCanvas):
def __init__(self, parent=None, width=5, height=4, dpi=100):
fig = Figure(figsize=(width, height), dpi=dpi)
FigureCanvas.__init__(self, fig)
self.setParent(parent)
self._instructions = []
self.axes = self.figure.add_subplot(111)
def paintEvent(self, event):
super().paintEvent(event)
painter = QtGui.QPainter(self)
painter.setRenderHint(QtGui.QPainter.Antialiasing, True)
width, height = self.get_width_height()
for x, y, rx, ry, br_color in self._instructions:
x_pixel, y_pixel_m = self.axes.transData.transform((x, y))
# In matplotlib, 0,0 is the lower left corner,
# whereas it's usually the upper right
# for most image software, so we'll flip the y-coor
y_pixel = height - y_pixel_m
painter.setBrush(QtGui.QColor(br_color))
painter.drawEllipse( QtCore.QPoint(x_pixel, y_pixel), rx, ry)
def create_oval(self, x, y, radius_x=2, radius_y=2, brush_color="red"):
self._instructions.append([x, y, radius_x, radius_y, brush_color])
self.update()
class MyPaintWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.canvas = PainterCanvas()
self.canvas.mpl_connect("button_press_event", self._on_left_click)
x = np.arange(0, 10, 0.1)
rand = [np.random.uniform(-0.1, 0.2) for _ in x]
y0 = np.exp(- (x - 5) ** 2 / 2) + rand
y1 = np.exp(- (x - 3) ** 2 / 0.5)
self.canvas.axes.plot(x, y0)
self.canvas.axes.plot(x, y1)
layout_canvas = QtWidgets.QVBoxLayout(self)
layout_canvas.addWidget(self.canvas)
self.canvasMenu = QtWidgets.QMenu(self)
self.canvasMenu.addAction("test")
self.canvas.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.canvas.customContextMenuRequested.connect(self._on_left_click)
def _on_left_click(self, event):
self.canvas.create_oval(event.xdata, event.ydata, brush_color="green")
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MyPaintWidget()
w.show()
sys.exit(app.exec_())
要添加点,我通过单击曲线添加了它们。我知道该代码无法完成我所要求的工作,但它只是为了生成一个图像来解释我的想法。
【问题讨论】:
一开始你是怎么做到的? 我添加了用于生成图像的代码。但是这段代码只是一个示例,用于生成图像来解释和说明我的想法。 我终于得到了我想要的,使用 Qslider 来控制我的曲线参数,并且我使用 pyqtgraph 非常快地绘制和刷新数据。 您可以添加一个解释您的解决方案的答案,以便将来也可以帮助其他人。 【参考方案1】:根据 mkrieger1 的建议,我将简要描述我的解决方案:
首先,我使用 PyQtGraph 绘制数据以比使用 Matplotlib 时更有效地绘制更新。
为了控制曲线,我使用了 QSlider(修改为支持双精度)来控制每条曲线的参数。当我移动一个滑块时,它会发出一个事件,在处理此事件的函数中,我使用函数 setData 更新我的 pyqtgraph plotwidget。
我的灵感来自于做我的双光标:Use float for QSlider 我使用了 pyqtgraph 文档:http://www.pyqtgraph.org/documentation/graphicsItems/plotdataitem.html
有太多代码无法放在那里,但解决方案在我的 GitHub 上的 spectrofit 项目中:https://github.com/fulmen27/SpectroFit(这是处理和研究恒星光谱的 UI)。解决方案在 spectrofit.tools.Interactive_Fit.py 文件中。
希望这能有所帮助!
【讨论】:
以上是关于通过在曲线上移动一个点来更新曲线的主要内容,如果未能解决你的问题,请参考以下文章