Skip to content

Commit

Permalink
simplify plotting further
Browse files Browse the repository at this point in the history
  • Loading branch information
bleykauf committed May 31, 2024
1 parent d11d15a commit 0082c89
Showing 1 changed file with 123 additions and 139 deletions.
262 changes: 123 additions & 139 deletions linien-gui/linien_gui/ui/plot_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,10 @@ def on_connection_established(self):
QtCore.QTimer.singleShot(100, self.listen_to_parameter_changes)

def listen_to_parameter_changes(self):
self.parent.parameters.sweep_center.add_callback(self.repaint_tick_strings)
self.parent.parameters.sweep_amplitude.add_callback(self.repaint_tick_strings)
self.parent.parameters.lock.add_callback(self.repaint_tick_strings)
self.repaint_tick_strings()

def repaint_tick_strings(self, *args):
self.picture = None
self.update()
self.parent.parameters.sweep_center.add_callback(self.on_lock_changed)
self.parent.parameters.sweep_amplitude.add_callback(self.on_lock_changed)
self.parent.parameters.lock.add_callback(self.on_lock_changed)
self.on_lock_changed()

def tickStrings(self, values, scale, spacing) -> list[str]:
if self.parent.parameters.lock.value:
Expand All @@ -99,6 +95,10 @@ def tickStrings(self, values, scale, spacing) -> list[str]:
precision_specifier = 2
return [f"{v:.{precision_specifier}f}" for v in values]

def on_lock_changed(self, *args) -> None:
self.picture = None
self.update()


class PlotWidget(pg.PlotWidget):
signal_power1 = pyqtSignal(float)
Expand All @@ -121,7 +121,13 @@ def __init__(self, *args, **kwargs):
# PlotItem
self.hideButtons()
# we have our own "reset view" button instead
self.init_reset_view_button()
self.reset_view_button = QtWidgets.QPushButton(self)
self.reset_view_button.setText("Reset view")
self.reset_view_button.setStyleSheet("padding: 10px; font-weight: bold")
icon = QtGui.QIcon.fromTheme("view-restore")
self.reset_view_button.setIcon(icon)
self.reset_view_button.clicked.connect(self.reset_view)
self.position_reset_view_button()

# copied from https://github.com/pyqtgraph/pyqtgraph/blob/master/pyqtgraph/graphicsItems/PlotItem/PlotItem.py#L133 # noqa: E501
# whenever something changes, we check whether to show "auto scale" button
Expand Down Expand Up @@ -192,9 +198,24 @@ def __init__(self, *args, **kwargs):
self.selection_running = False
self.selection_boundaries = None

self.init_overlays()
self.init_lock_target_line()
self.overlay = pg.LinearRegionItem(values=(0, 0), movable=False)
self.overlay.setVisible(False)
self.addItem(self.overlay)

self.boundary_overlays = [
pg.LinearRegionItem(values=(0, 0), movable=False, brush=(0, 0, 0, 200))
for _ in range(2)
]
for i, overlay in enumerate(self.boundary_overlays):
overlay.setVisible(False)
# make outer borders invisible, see
# https://github.com/pyqtgraph/pyqtgraph/issues/462
overlay.lines[i].setPen((0, 0, 0, 0))
self.addItem(overlay)

self.lock_target_line = pg.InfiniteLine(movable=False)
self.lock_target_line.setValue(1000)
self.addItem(self.lock_target_line)
self._fixed_opengl_bug = False

self.last_plot_time = 0
Expand All @@ -208,78 +229,47 @@ def on_connection_established(self):
self.parameters = self.app.parameters
self.control = self.app.control

def on_plot_settings_changed(*args):
pen_width = self.app.settings.plot_line_width.value

for curve, color in {
self.signal1: Color.SPECTRUM1,
self.signal2: Color.SPECTRUM2,
self.combined_signal: Color.SPECTRUM_COMBINED,
self.control_signal: Color.CONTROL_SIGNAL,
self.control_signal_history: Color.CONTROL_SIGNAL_HISTORY,
self.slow_history: Color.SLOW_HISTORY,
self.monitor_signal_history: Color.MONITOR_SIGNAL_HISTORY,
}.items():
r, g, b, _ = getattr(
self.app.settings, f"plot_color_{color.value}"
).value
a = self.app.settings.plot_line_opacity.value
curve.setPen(pg.mkPen((r, g, b, a), width=pen_width))

for color_idx in range(N_COLORS):
getattr(self.app.settings, f"plot_color_{color_idx}").add_callback(
on_plot_settings_changed
self.on_plot_settings_changed
)
self.app.settings.plot_line_width.add_callback(on_plot_settings_changed)
self.app.settings.plot_line_opacity.add_callback(on_plot_settings_changed)
self.app.settings.plot_line_width.add_callback(self.on_plot_settings_changed)
self.app.settings.plot_line_opacity.add_callback(self.on_plot_settings_changed)

self.control_signal_history_data = self.parameters.control_signal_history.value
self.monitor_signal_history_data = self.parameters.monitor_signal_history.value

self.parameters.to_plot.add_callback(self.on_new_plot_data_received)

def on_autolock_selection_changed(value):
if value:
self.parameters.optimization_selection.value = False
self.enable_area_selection(selectable_width=0.99)
self.pause_plot_and_cache_data()
elif not self.parameters.optimization_selection.value:
self.disable_area_selection()
self.resume_plot_and_clear_cache()

self.parameters.autolock_selection.add_callback(on_autolock_selection_changed)

def on_optimization_selection_changed(value):
if value:
self.parameters.autolock_selection.value = False
self.enable_area_selection(selectable_width=0.75)
self.pause_plot_and_cache_data()
elif not self.parameters.autolock_selection.value:
self.disable_area_selection()
self.resume_plot_and_clear_cache()

self.parameters.autolock_selection.add_callback(
self.on_autolock_selection_changed
)
self.parameters.optimization_selection.add_callback(
on_optimization_selection_changed
self.on_optimization_selection_changed
)

def show_or_hide_crosshair(automatic_mode: bool) -> None:
self.crosshair.setVisible(not automatic_mode)

self.parameters.automatic_mode.add_callback(show_or_hide_crosshair)

def set_xaxis_label(lock: bool) -> None:
if not lock:
self.setLabel("bottom", "sweep voltage", units="V")
else:
self.setLabel("bottom", "time", units="µs")

self.parameters.lock.add_callback(set_xaxis_label)
self.parameters.automatic_mode.add_callback(self.on_automatic_mode_changed)
self.parameters.lock.add_callback(self.on_lock_changed)

def _to_data_coords(self, event):
pos = self.plotItem.vb.mapSceneToView(event.pos())
x, y = pos.x(), pos.y()
return x, y

def _within_boundaries(self, x):
boundaries = (
self.selection_boundaries if self.selection_running else [0, N_POINTS]
)

if x < boundaries[0]:
return boundaries[0]
if x > boundaries[1]:
return boundaries[1]
return x

def keyPressEvent(self, event):
# we listen here in addition to the main window because some events are only
# caught here
self.keyPressed.emit(event.key())

def mouseMoveEvent(self, event):
if not self.selection_running:
super().mouseMoveEvent(event)
Expand All @@ -293,62 +283,6 @@ def mouseMoveEvent(self, event):
x = self._within_boundaries(x)
self.set_selection_overlay(x0, x - x0)

def init_overlays(self):
self.overlay = pg.LinearRegionItem(values=(0, 0), movable=False)
self.overlay.setVisible(False)
self.addItem(self.overlay)

self.boundary_overlays = [
pg.LinearRegionItem(
values=(0, 0),
movable=False,
brush=(0, 0, 0, 200),
)
for i in range(2)
]
for i, overlay in enumerate(self.boundary_overlays):
overlay.setVisible(False)
# make outer borders invisible, see
# https://github.com/pyqtgraph/pyqtgraph/issues/462
overlay.lines[i].setPen((0, 0, 0, 0))
self.addItem(overlay)

def init_lock_target_line(self):
self.lock_target_line = pg.InfiniteLine(movable=False)
self.lock_target_line.setValue(1000)
self.addItem(self.lock_target_line)

def set_selection_overlay(self, x_start, width):
self.overlay.setRegion((x_start, x_start + width))

def mousePressEvent(self, event):
super().mousePressEvent(event)

if self.selection_running:
if event.button() == QtCore.Qt.RightButton:
return

x, y = self._to_data_coords(event)

if self.selection_running:
if x < self.selection_boundaries[0] or x > self.selection_boundaries[1]:
return

self.touch_start = x, y
self.set_selection_overlay(x, 0)
self.overlay.setVisible(True)

def _within_boundaries(self, x):
boundaries = (
self.selection_boundaries if self.selection_running else [0, N_POINTS]
)

if x < boundaries[0]:
return boundaries[0]
if x > boundaries[1]:
return boundaries[1]
return x

def mouseReleaseEvent(self, event):
super().mouseReleaseEvent(event)

Expand Down Expand Up @@ -406,6 +340,70 @@ def mouseReleaseEvent(self, event):
self.overlay.setVisible(False)
self.touch_start = None

def on_plot_settings_changed(self, *args):
pen_width = self.app.settings.plot_line_width.value

for curve, color in {
self.signal1: Color.SPECTRUM1,
self.signal2: Color.SPECTRUM2,
self.combined_signal: Color.SPECTRUM_COMBINED,
self.control_signal: Color.CONTROL_SIGNAL,
self.control_signal_history: Color.CONTROL_SIGNAL_HISTORY,
self.slow_history: Color.SLOW_HISTORY,
self.monitor_signal_history: Color.MONITOR_SIGNAL_HISTORY,
}.items():
r, g, b, _ = getattr(self.app.settings, f"plot_color_{color.value}").value
a = self.app.settings.plot_line_opacity.value
curve.setPen(pg.mkPen((r, g, b, a), width=pen_width))

def on_autolock_selection_changed(self, value):
if value:
self.parameters.optimization_selection.value = False
self.enable_area_selection(selectable_width=0.99)
self.pause_plot_and_cache_data()
elif not self.parameters.optimization_selection.value:
self.disable_area_selection()
self.resume_plot_and_clear_cache()

def on_optimization_selection_changed(self, value):
if value:
self.parameters.autolock_selection.value = False
self.enable_area_selection(selectable_width=0.75)
self.pause_plot_and_cache_data()
elif not self.parameters.autolock_selection.value:
self.disable_area_selection()
self.resume_plot_and_clear_cache()

def on_automatic_mode_changed(self, automatic_mode: bool) -> None:
"""Show or hide crosshair"""
self.crosshair.setVisible(not automatic_mode)

def on_lock_changed(self, lock: bool) -> None:
if not lock:
self.setLabel("bottom", "sweep voltage", units="V")
else:
self.setLabel("bottom", "time", units="µs")

def set_selection_overlay(self, x_start, width):
self.overlay.setRegion((x_start, x_start + width))

def mousePressEvent(self, event):
super().mousePressEvent(event)

if self.selection_running:
if event.button() == QtCore.Qt.RightButton:
return

x, y = self._to_data_coords(event)

if self.selection_running:
if x < self.selection_boundaries[0] or x > self.selection_boundaries[1]:
return

self.touch_start = x, y
self.set_selection_overlay(x, 0)
self.overlay.setVisible(True)

def on_new_plot_data_received(self, to_plot):
time_beginning = time()

Expand Down Expand Up @@ -484,13 +482,13 @@ def on_new_plot_data_received(self, to_plot):
self.plot_autolock_target_line(None)
else:
dual_channel = self.parameters.dual_channel.value
self.signal1.setVisible(dual_channel)
self.signal1.setVisible(True)
monitor_signal = to_plot.get("monitor_signal")
error_signal_2 = to_plot.get("error_signal_2")
self.signal2.setVisible(
error_signal_2 is not None or monitor_signal is not None
)
self.combined_signal.setVisible(True)
self.combined_signal.setVisible(dual_channel)
self.control_signal.setVisible(False)
self.control_signal_history.setVisible(False)
self.slow_history.setVisible(False)
Expand Down Expand Up @@ -661,11 +659,6 @@ def plot_autolock_target_line(self, combined_error_signal):
else:
self.lock_target_line.setVisible(False)

def keyPressEvent(self, event):
# we listen here in addition to the main window because some events are only
# caught here
self.keyPressed.emit(event.key())

def update_signal_history(self, to_plot):
update_signal_history(
self.control_signal_history_data,
Expand Down Expand Up @@ -741,15 +734,6 @@ def resume_plot_and_clear_cache(self):
self._plot_paused = False
self._cached_plot_data = []

def init_reset_view_button(self):
self.reset_view_button = QtWidgets.QPushButton(self)
self.reset_view_button.setText("Reset view")
self.reset_view_button.setStyleSheet("padding: 10px; font-weight: bold")
icon = QtGui.QIcon.fromTheme("view-restore")
self.reset_view_button.setIcon(icon)
self.reset_view_button.clicked.connect(self.reset_view)
self.position_reset_view_button()

# called when widget is resized
def position_reset_view_button(self):
pos = QtCore.QPoint(
Expand Down

0 comments on commit 0082c89

Please sign in to comment.