mirror of
https://github.com/bec-project/bec_widgets.git
synced 2026-03-08 01:37:52 +01:00
feat: added qt_utils package with general Crosshair function
* only emits int -> suitable for 2D coordinates but not for 1D plot
This commit is contained in:
@@ -61,7 +61,7 @@ class BasicPlot(QtWidgets.QWidget):
|
||||
"symbol": "o",
|
||||
"symbolSize": 10,
|
||||
}
|
||||
color_list = ["#384c6b", "#e28a2b", "#5E3023", "#e41a1c", "#984e83", "#4daf4a"]
|
||||
|
||||
color_list = BasicPlot.golden_angle_color(colormap="CET-R2", num=len(self.y_value_list))
|
||||
|
||||
# setup plots - GraphicsLayoutWidget
|
||||
@@ -126,7 +126,7 @@ class BasicPlot(QtWidgets.QWidget):
|
||||
|
||||
# Debug functions
|
||||
self.pushButton_debug.clicked.connect(self.generate_2D_data_update)
|
||||
self.generate_2D_data()
|
||||
# self.generate_2D_data()
|
||||
|
||||
self._current_proj = None
|
||||
self._current_metadata_ep = "px_stream/projection_{}/metadata"
|
||||
@@ -187,18 +187,18 @@ class BasicPlot(QtWidgets.QWidget):
|
||||
closest_point = self.closest_x_y_value(
|
||||
mousePoint.x(), self.plotter_data_x[0], self.plotter_data_y[0]
|
||||
)
|
||||
self.precision = 3
|
||||
ii = 0
|
||||
y_value = self.y_value_list[ii]
|
||||
x_data = f"{10**closest_point[0]:.{self.precision}f}"
|
||||
y_data = f"{10**closest_point[1]:.{self.precision}f}"
|
||||
|
||||
# Write coordinate to QTable
|
||||
self.mouse_table.setItem(ii, 1, QTableWidgetItem(str(y_value)))
|
||||
self.mouse_table.setItem(ii, 2, QTableWidgetItem(str(x_data)))
|
||||
self.mouse_table.setItem(ii, 3, QTableWidgetItem(str(y_data)))
|
||||
|
||||
self.mouse_table.resizeColumnsToContents()
|
||||
# self.precision = 3
|
||||
# ii = 0
|
||||
# y_value = self.y_value_list[ii]
|
||||
# x_data = f"{10**closest_point[0]:.{self.precision}f}"
|
||||
# y_data = f"{10**closest_point[1]:.{self.precision}f}"
|
||||
#
|
||||
# # Write coordinate to QTable
|
||||
# self.mouse_table.setItem(ii, 1, QTableWidgetItem(str(y_value)))
|
||||
# self.mouse_table.setItem(ii, 2, QTableWidgetItem(str(x_data)))
|
||||
# self.mouse_table.setItem(ii, 3, QTableWidgetItem(str(y_data)))
|
||||
#
|
||||
# self.mouse_table.resizeColumnsToContents()
|
||||
|
||||
def closest_x_y_value(self, input_value, list_x, list_y) -> tuple:
|
||||
"""
|
||||
@@ -382,7 +382,7 @@ class BasicPlot(QtWidgets.QWidget):
|
||||
time.sleep(0.1)
|
||||
continue
|
||||
endpoint = f"px_stream/projection_{self._current_proj}/data"
|
||||
msgs = client.producer.lrange(topic=endpoint, start=0, end=0)
|
||||
msgs = client.producer.lrange(topic=endpoint, start=-1, end=-1)
|
||||
data = [BECMessage.DeviceMessage.loads(msg) for msg in msgs]
|
||||
if not data:
|
||||
continue
|
||||
|
||||
0
bec_widgets/qt_utils/__init__.py
Normal file
0
bec_widgets/qt_utils/__init__.py
Normal file
46
bec_widgets/qt_utils/crosshair.py
Normal file
46
bec_widgets/qt_utils/crosshair.py
Normal file
@@ -0,0 +1,46 @@
|
||||
import pyqtgraph as pg
|
||||
import numpy as np
|
||||
from PyQt5.QtCore import pyqtSignal, QObject
|
||||
|
||||
|
||||
class Crosshair(QObject):
|
||||
coordinatesChanged = pyqtSignal(float, float)
|
||||
dataPointClicked = pyqtSignal(float, float)
|
||||
|
||||
def __init__(self, plot_item, is_image=False, parent=None):
|
||||
super().__init__(parent)
|
||||
self.plot_item = plot_item
|
||||
self.data_shape = None
|
||||
self.is_image = is_image
|
||||
self.v_line = pg.InfiniteLine(angle=90, movable=False)
|
||||
self.h_line = pg.InfiniteLine(angle=0, movable=False)
|
||||
self.plot_item.addItem(self.v_line, ignoreBounds=True)
|
||||
self.plot_item.addItem(self.h_line, ignoreBounds=True)
|
||||
self.proxy = pg.SignalProxy(
|
||||
self.plot_item.scene().sigMouseMoved, rateLimit=60, slot=self.mouse_moved
|
||||
)
|
||||
self.plot_item.scene().sigMouseClicked.connect(self.mouse_clicked)
|
||||
|
||||
def mouse_moved(self, event):
|
||||
pos = event[0]
|
||||
if self.data_shape is not None and self.plot_item.vb.sceneBoundingRect().contains(pos):
|
||||
mouse_point = self.plot_item.vb.mapSceneToView(pos)
|
||||
x = int(np.clip(np.round(mouse_point.x()), 0, self.data_shape[1] - 1))
|
||||
y = int(np.clip(np.round(mouse_point.y()), 0, self.data_shape[0] - 1))
|
||||
self.v_line.setPos(x)
|
||||
self.h_line.setPos(y)
|
||||
self.coordinatesChanged.emit(x, y)
|
||||
|
||||
def mouse_clicked(self, event):
|
||||
if self.data_shape is not None and self.plot_item.vb.sceneBoundingRect().contains(
|
||||
event._scenePos
|
||||
):
|
||||
mouse_point = self.plot_item.vb.mapSceneToView(event._scenePos)
|
||||
x = int(np.clip(np.round(mouse_point.x()), 0, self.data_shape[1] - 1))
|
||||
y = int(np.clip(np.round(mouse_point.y()), 0, self.data_shape[0] - 1))
|
||||
self.v_line.setPos(x)
|
||||
self.h_line.setPos(y)
|
||||
self.dataPointClicked.emit(x, y)
|
||||
|
||||
def set_data_shape(self, shape):
|
||||
self.data_shape = shape
|
||||
71
bec_widgets/qt_utils/crosshair_example.py
Normal file
71
bec_widgets/qt_utils/crosshair_example.py
Normal file
@@ -0,0 +1,71 @@
|
||||
import pyqtgraph as pg
|
||||
import numpy as np
|
||||
|
||||
from crosshair import Crosshair
|
||||
|
||||
|
||||
def add_crosshair(plot_item, is_image=False):
|
||||
return Crosshair(plot_item, is_image)
|
||||
|
||||
|
||||
app = pg.mkQApp()
|
||||
win = pg.GraphicsLayoutWidget(show=True)
|
||||
win.resize(1000, 500)
|
||||
|
||||
#####################
|
||||
# 1D Plot with labels
|
||||
#####################
|
||||
label_1d_move = win.addLabel("1D move label", row=0, col=0)
|
||||
label_1d_click = win.addLabel("1D click label", row=1, col=0)
|
||||
plot_item_1d = win.addPlot(row=2, col=0)
|
||||
x_data = np.linspace(0, 10, 1000)
|
||||
y_data = np.sin(x_data)
|
||||
plot_item_1d.plot(x_data, y_data)
|
||||
#
|
||||
crosshair_1d = add_crosshair(plot_item_1d)
|
||||
crosshair_1d.set_data_shape((len(y_data), len(x_data)))
|
||||
|
||||
|
||||
#
|
||||
def on_coordinates_changed_1d(x, y):
|
||||
label_1d_move.setText(f"1D Moved: ({x}, {y})")
|
||||
|
||||
|
||||
def on_data_point_clicked_1d(x, y):
|
||||
label_1d_click.setText(f"1D Clicked: ({x}, {y})")
|
||||
|
||||
|
||||
#
|
||||
crosshair_1d.coordinatesChanged.connect(on_coordinates_changed_1d)
|
||||
crosshair_1d.dataPointClicked.connect(on_data_point_clicked_1d)
|
||||
|
||||
#####################
|
||||
# 2D Plot with labels
|
||||
#####################
|
||||
label_2d_move = win.addLabel("2D move label", row=0, col=1)
|
||||
label_2d_click = win.addLabel("2D click label", row=1, col=1)
|
||||
plot_item_2d = win.addPlot(row=2, col=1)
|
||||
|
||||
img = np.random.normal(size=(100, 100))
|
||||
image_item = pg.ImageItem(img)
|
||||
plot_item_2d.addItem(image_item)
|
||||
|
||||
crosshair_2d = add_crosshair(plot_item_2d, is_image=True)
|
||||
crosshair_2d.set_data_shape(img.shape)
|
||||
|
||||
|
||||
#
|
||||
def on_coordinates_changed_2d(x, y):
|
||||
label_2d_move.setText(f"2D Moved: ({x}, {y})")
|
||||
|
||||
|
||||
def on_data_point_clicked_2d(x, y):
|
||||
label_2d_click.setText(f"2D Clicked: ({x}, {y})")
|
||||
|
||||
|
||||
#
|
||||
crosshair_2d.coordinatesChanged.connect(on_coordinates_changed_2d)
|
||||
crosshair_2d.dataPointClicked.connect(on_data_point_clicked_2d)
|
||||
|
||||
if __name__ == "__main__":
|
||||
pg.exec()
|
||||
Reference in New Issue
Block a user