Hi everyone !
This is my first object-oriented project, thus some parts could be wrote in a better way (advices would be appreciate..
)
I manage do build a code that allows points to be drag verticaly with mouse event.
https://ibb.co/CVvH0ww
https://ibb.co/P1MCJCp
I am able to retrieve the new coordinates, but only within the DraggablePoint Class.
Now I want the new coordinates from the drag point to be update in a list, in real time.
I mean, whenever the plot change with a mouse event, the list value should be update.
The main issue is that I don't know how to access and retrieve coordinates values outside of the event class
I tried to store the new coordinates in an attributes of the instance DraggablePoint, but didn't manage to get what I want..
Once again, I am quite new in this object-oriented world
Could someone give me advices ?
Thanks a lot !
The DraggablePoint class is the Following :
This is my first object-oriented project, thus some parts could be wrote in a better way (advices would be appreciate..
)I manage do build a code that allows points to be drag verticaly with mouse event.
https://ibb.co/CVvH0ww
https://ibb.co/P1MCJCp
I am able to retrieve the new coordinates, but only within the DraggablePoint Class.
Now I want the new coordinates from the drag point to be update in a list, in real time.
I mean, whenever the plot change with a mouse event, the list value should be update.
The main issue is that I don't know how to access and retrieve coordinates values outside of the event class
I tried to store the new coordinates in an attributes of the instance DraggablePoint, but didn't manage to get what I want..
Once again, I am quite new in this object-oriented world
Could someone give me advices ?
Thanks a lot !
The DraggablePoint class is the Following :
# drag.py
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib.lines import Line2D
import PySide2.QtCore as QtCore
class DraggablePoint:
lock = None # only one can be animated at a time
def __init__(self, parent, x=0.1, y=0.1, size=0.1):
global dragx, dragy
self.parent = parent
self.point = patches.Ellipse((x, y), size, size , fc='r', alpha=0.5, edgecolor='r')
self.x = x
self.y = y
parent.fig.axes[0].add_patch(self.point)
self.press = None
self.background = None
self.connect()
# if another point already exist we draw a line
if self.parent.list_points:
line_x = [self.parent.list_points[-1].x, self.x]
line_y = [self.parent.list_points[-1].y, self.y]
self.line = Line2D(line_x, line_y, color='r', alpha=0.5)
parent.fig.axes[0].add_line(self.line)
self.coordinates = []
def connect(self):
'connect to all the events we need'
self.cidpress = self.point.figure.canvas.mpl_connect('button_press_event', self.on_press)
self.cidrelease = self.point.figure.canvas.mpl_connect('button_release_event', self.on_release)
self.cidmotion = self.point.figure.canvas.mpl_connect('motion_notify_event', self.on_motion)
def on_press(self, event):
if event.inaxes != self.point.axes: return
if DraggablePoint.lock is not None: return
contains, attrd = self.point.contains(event)
if not contains: return
self.press = (self.point.center), event.xdata, event.ydata
DraggablePoint.lock = self
# draw everything but the selected rectangle and store the pixel buffer
canvas = self.point.figure.canvas
axes = self.point.axes
self.point.set_animated(True)
# TODO also the line of some other points needs to be released
point_number = self.parent.list_points.index(self)
if self == self.parent.list_points[0]:
self.parent.list_points[1].line.set_animated(True)
elif self == self.parent.list_points[-1]:
self.line.set_animated(True)
else:
self.line.set_animated(True)
self.parent.list_points[point_number+1].line.set_animated(True)
canvas.draw()
self.background = canvas.copy_from_bbox(self.point.axes.bbox)
# now redraw just the rectangle
axes.draw_artist(self.point)
# and blit just the redrawn area
canvas.blit(axes.bbox)
def on_motion(self, event):
if DraggablePoint.lock is not self:
return
if event.inaxes != self.point.axes: return
self.point.center, xpress, ypress = self.press
dy = event.ydata - ypress
self.point.center = (self.point.center[0], self.point.center[1]+dy)
canvas = self.point.figure.canvas
axes = self.point.axes
# restore the background region
canvas.restore_region(self.background)
# redraw just the current rectangle
axes.draw_artist(self.point)
point_number = self.parent.list_points.index(self)
self.x = self.point.center[0]
self.y = self.point.center[1]
# We check if the point is A or B
if self == self.parent.list_points[0]:
# or we draw the other line of the point
self.parent.list_points[1].line.set_animated(True)
axes.draw_artist(self.parent.list_points[1].line)
elif self == self.parent.list_points[-1]:
# we draw the line of the point
axes.draw_artist(self.line)
else:
# we draw the line of the point
axes.draw_artist(self.line)
#self.parent.list_points[point_number+1].line.set_animated(True)
axes.draw_artist(self.parent.list_points[point_number+1].line)
if self == self.parent.list_points[0]:
# The first point is especial because it has no line
line_x = [self.x, self.parent.list_points[1].x]
line_y = [self.y, self.parent.list_points[1].y]
# this is were the line is updated
self.parent.list_points[1].line.set_data(line_x, line_y)
elif self == self.parent.list_points[-1]:
line_x = [self.parent.list_points[-2].x, self.x]
line_y = [self.parent.list_points[-2].y, self.y]
self.line.set_data(line_x, line_y)
else:
# The first point is especial because it has no line
line_x = [self.x, self.parent.list_points[point_number+1].x]
line_y = [self.y, self.parent.list_points[point_number+1].y]
# this is were the line is updated
self.parent.list_points[point_number+1].line.set_data(line_x, line_y)
line_x = [self.parent.list_points[point_number-1].x, self.x]
line_y = [self.parent.list_points[point_number-1].y, self.y]
self.line.set_data(line_x, line_y)
# blit just the redrawn area
canvas.blit(axes.bbox)
def on_release(self, event):
'on release we reset the press data'
if DraggablePoint.lock is not self:
return
self.press = None
DraggablePoint.lock = None
# turn off the rect animation property and reset the background
self.point.set_animated(False)
point_number = self.parent.list_points.index(self)
if self == self.parent.list_points[0]:
self.parent.list_points[1].line.set_animated(False)
elif self == self.parent.list_points[-1]:
self.line.set_animated(False)
else:
self.line.set_animated(False)
self.parent.list_points[point_number+1].line.set_animated(False)
self.background = None
# redraw the full figure
self.point.figure.canvas.draw()
self.x = self.point.center[0]
self.y = self.point.center[1]
self.coordinates.append([self.x, self.y])
#print("Access from Class", self.x)
#print("Access from Class", self.y)
print("Access from Class", self.coordinates)
def disconnect(self):
'disconnect all the stored connection ids'
self.point.figure.canvas.mpl_disconnect(self.cidpress)
self.point.figure.canvas.mpl_disconnect(self.cidrelease)
self.point.figure.canvas.mpl_disconnect(self.cidmotion)The main piece of code : #-------------------------------------------------------------------------------
# Name: module5
# Purpose:
#
# Author: jguillerm
#
# Created: 05/01/2023
# Copyright: (c) jguillerm 2023
# Licence: <your licence>
#-------------------------------------------------------------------------------
import sys
import matplotlib
matplotlib.use("Qt5Agg")
from PyQt5 import QtWidgets, QtGui
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import PySide2.QtCore as QtCore
# Personnal modules
from drag import DraggablePoint
class MyGraph(FigureCanvas):
"""A canvas that updates itself every second with a new plot."""
def __init__(self, parent=None, width=5, height=4, dpi=100):
PK = [0, 10, 20, 30, 40, 50]
FE = [251, 252, 248, 250, 251, 253]
self.fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = self.fig.add_subplot()
self.axes.grid(True)
self.axes.set_xlim([0,50])
self.axes.set_ylim([240,260])
FigureCanvas.__init__(self, self.fig)
self.setParent(parent)
FigureCanvas.setSizePolicy(self,
QtWidgets.QSizePolicy.Expanding,
QtWidgets.QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
# To store the 2 draggable points
self.list_points = []
self.show()
self.plotDraggablePoints(PK, FE)
def plotDraggablePoints(self, listX, listY, size=1):
"""Plot and define the 2 draggable points of the baseline"""
n = len(listX)
for i in range(0,n):
DragPoint = DraggablePoint(self, listX[i], listY[i], size)
self.list_points.append(DragPoint)
#print(" Access from script ", DragPoint.x)
#print(" Access from script ", DragPoint.y)
self.updateFigure()
print(listY)
def clearFigure(self):
"""Clear the graph"""
self.axes.clear()
self.axes.grid(True)
del(self.list_points[:])
self.updateFigure()
def updateFigure(self):
"""Update the graph. Necessary, to call after each plot"""
self.draw()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
ex = MyGraph()
sys.exit(app.exec_())
print(PK)
