Skip to content

Commit 41b9665

Browse files
committed
better plotting and others
1 parent c0f9bc1 commit 41b9665

File tree

8 files changed

+102
-26
lines changed

8 files changed

+102
-26
lines changed

omc3_gui/plotting/classes.py

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import pyqtgraph as pg
88
from accwidgets.graph import StaticPlotWidget
99
from accwidgets.graph.widgets.plotitem import ExViewBox
10+
from accwidgets.graph.widgets.plotwidget import GridOrientationOptions
1011
from qtpy.QtCore import Signal
1112

1213

@@ -39,25 +40,31 @@ def __init__(self, *args, **kwargs) -> None:
3940
def plots(self) -> tuple[pg.PlotWidget, pg.PlotWidget]:
4041
return (self.top, self.bottom)
4142

42-
4343
def clear(self) -> None:
4444
for plot in self.plots:
4545
plot.clear()
4646

47+
def set_connect_x(self, connect: bool) -> None:
48+
if connect:
49+
self.top.setXLink(self.bottom)
50+
else:
51+
self.top.setXLink(None)
52+
self.bottom.setXLink(None)
4753

48-
def connect_x(self) -> None:
49-
pass
50-
51-
def connect_y(self) -> None:
52-
pass
54+
def set_connect_y(self, connect: bool) -> None:
55+
if connect:
56+
self.top.setYLink(self.bottom)
57+
else:
58+
self.top.setYLink(None)
59+
self.bottom.setYLink(None)
5360

5461

5562
class PlotWidget(StaticPlotWidget):
5663

5764
def __init__(self, *args, **kwargs) -> None:
5865
super().__init__(*args, **kwargs, viewBox=ZoomingViewBox()) # requires accwidgets >= 3.0.11
5966
self.setBackground("w")
60-
67+
self._set_show_grid(GridOrientationOptions.Both)
6168

6269
class ZoomingViewBox(ExViewBox):
6370
""" ViewBox that imitates the bahavior of the Java-GUI a bit closer.
@@ -68,6 +75,11 @@ def __init__(self, *args, **kwargs) -> None:
6875
super().__init__(*args, **kwargs)
6976
self.setMouseMode(ZoomingViewBox.RectMode) # mode that makes zooming rectangles
7077

78+
def suggestPadding(self, axis):
79+
if axis == 0:
80+
return 0.0 # disable padding for x axis
81+
return super().suggestPadding(axis)
82+
7183
# def mouseDragEvent(self, ev):
7284

7385
# if ev.button() == QtCore.Qt.RightButton:

omc3_gui/segment_by_segment.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
GUI:
1111
- Load segments from file or folder (check sbs/sbs_ files)
1212
- Save segments to file
13-
- Autoload segments when opening measurement folder
1413
- Pass measurement folders via cli args.
1514
1615
Settings:
@@ -22,7 +21,6 @@
2221
- Going back through plot history on double-click
2322
2423
"""
25-
2624
import sys
2725
from omc3_gui.segment_by_segment.main_controller import SbSController
2826
from omc3_gui.utils.log_handler import init_logging
@@ -34,4 +32,5 @@
3432

3533
if __name__ == "__main__":
3634
init_logging()
37-
sys.exit(SbSController.run_application(measurements=["/mnt/volume/jdilly/projects/omc3_gui/tst_SBStest_wACD/measured_optics"]))
35+
# sys.exit(SbSController.run_application(measurements=["/mnt/volume/jdilly/projects/omc3_gui/tst_SBStest_wACD/measured_optics", "/afs/cern.ch/work/j/josch/temp.bbgui_output/2025-02-19/LHCB1/Results/omc3_B1_30cm_with_old_local_corrections/"]))
36+
sys.exit(SbSController.run_application())

omc3_gui/segment_by_segment/defaults.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,56 @@
44
55
Defaults for segment by segment.
66
"""
7+
from __future__ import annotations
8+
9+
from typing import TYPE_CHECKING
710
from omc3_gui.segment_by_segment.segment_model import SegmentTuple
811

12+
if TYPE_CHECKING:
13+
from omc3_gui.segment_by_segment.measurement_model import OpticsMeasurement
14+
915
DEFAULT_SEGMENTS =(
1016
SegmentTuple("IP1", "BPM.12L1", "BPM.12R1"),
1117
SegmentTuple("IP2", "BPM.12L2", "BPM.12R2"),
1218
SegmentTuple("IP5", "BPM.12L5", "BPM.12R5"),
1319
SegmentTuple("IP8", "BPM.12L8", "BPM.12R8"),
14-
)
20+
)
21+
22+
23+
LHC_ARCS = ('78', '81', '12', '23', '34', '45', '56', '67') # 78 needs to be before 81 to make lr fit
24+
LHC_CORRECTORS = (
25+
"kqf.a{}",
26+
"kqd.a{}",
27+
"kqt12.{}{}b{}",
28+
"kqtl11.{}{}b{}",
29+
"kq10.{}{}b{}",
30+
"kq9.{}{}b{}",
31+
"kq8.{}{}b{}",
32+
"kq7.{}{}b{}",
33+
"kq6.{}{}b{}",
34+
"kq5.{}{}b{}",
35+
"kq4.{}{}b{}",
36+
"kqx.{}{}b{}",
37+
"kqsx3.{}{}b{}",
38+
"ktqx2.{}{}b{}",
39+
"ktqx1.{}{}b{}",
40+
"kqx.{}{}b{}",
41+
)
42+
43+
def get_default_correctors(measurement: OpticsMeasurement) -> str:
44+
text = ""
45+
if measurement.accel == "lhc":
46+
text = ""
47+
for ip in (1, 2, 5, 8):
48+
text += f"! IP{ip} -----\n"
49+
arcs = [arc for arc in LHC_ARCS if str(ip) in arc]
50+
for arc, side in zip(arcs, "lr"):
51+
lhc_correctors = LHC_CORRECTORS if side == "l" else LHC_CORRECTORS[::-1]
52+
for corrector in lhc_correctors:
53+
if "a" in corrector:
54+
corrector = corrector.format(arc)
55+
else:
56+
corrector = corrector.format(side, ip, measurement.beam)
57+
text += f"! {corrector} = {corrector};\n"
58+
text += "\n"
59+
return text

omc3_gui/segment_by_segment/main_controller.py

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@
1212
from typing import TYPE_CHECKING
1313

1414
from omc3.sbs_propagation import segment_by_segment
15+
from omc3.segment_by_segment.constants import corrections_madx
1516
from qtpy import QtWidgets
1617
from qtpy.QtCore import Slot
1718

18-
from omc3_gui.segment_by_segment.defaults import DEFAULT_SEGMENTS
19+
from omc3_gui.segment_by_segment.defaults import DEFAULT_SEGMENTS, get_default_correctors
1920
from omc3_gui.segment_by_segment.plotting import plot_segment_data
2021
from omc3_gui.segment_by_segment.settings import PlotSettings, Settings
2122
from omc3_gui.segment_by_segment.main_model import SegmentTableModel
@@ -70,7 +71,7 @@ def connect_signals(self):
7071
view.add_settings_to_menu(
7172
menu="View",
7273
settings=self.settings.plotting,
73-
hook=partial(self.plot, weak=True),
74+
hook=partial(self.plot, weak=True), # update plots if possible
7475
)
7576

7677
# Measurements -------------------------------------------------------------
@@ -421,6 +422,11 @@ def edit_corrections(self) -> None:
421422
# Open the TextEditor for the selected correction file ---
422423
LOGGER.debug(f"Opening TextEditor for correction file: {correction_file}.")
423424
edit_dialog = TextEditorDialog(correction_file)
425+
426+
if not correction_file.exists() and self.settings.main.suggest_correctors:
427+
text = get_default_correctors(selected_measurements[0]) # bit hacky but ok for now?
428+
edit_dialog.text_edit.setPlainText(text)
429+
424430
edit_dialog.exec_()
425431

426432

@@ -659,6 +665,12 @@ def load_segments_for_measurement(self, measurement: OpticsMeasurement):
659665
segment = SegmentDataModel(measurement, *segment_tuple)
660666
measurement.try_add_segment(segment)
661667

668+
for segment in measurement.segments:
669+
corrections = measurement.output_dir / corrections_madx.format(segment.name)
670+
if corrections.exists():
671+
measurement.corrections = corrections
672+
break # for now they should all be the same corrections
673+
662674
@Slot()
663675
def save_segments(self):
664676
LOGGER.debug("Saving segments to a file.")
@@ -726,26 +738,30 @@ def clear_all():
726738
)
727739

728740
# For Real Use: Run Task ---
729-
# LOGGER.info(f"Starting {measurement_task.message}")
730-
# self._add_running_task(task=measurement_task)
731-
# measurement_task.start()
741+
LOGGER.info(f"Starting {measurement_task.message}")
742+
self._add_running_task(task=measurement_task)
743+
measurement_task.start()
732744

733745
# For Debugging: Start sbs directly ---
734-
sbs_function()
735-
clear_all()
736-
LOGGER.info(f"Finished {measurement_task.message}")
746+
# sbs_function()
747+
# clear_all()
748+
# LOGGER.info(f"Finished {measurement_task.message}")
737749
# -------------------------------------
738750

739751
# Plotting ---------------------------------------------------------------------
740752
def plot(self, weak: bool = False):
741753
""" Trigger a plot update with the currently selected segments. """
742754
view: SbSWindow = self._view
743755
settings: PlotSettings = self.settings.plotting
756+
definition, widget = view.get_current_tab()
744757

745758
if not settings.forward and not settings.backward:
746759
LOGGER.error("Please enable at least one propagation method to show.")
747760
return
748761

762+
widget.set_connect_x(settings.connect_x)
763+
widget.set_connect_y(settings.connect_y)
764+
749765
segments = view.get_selected_segments()
750766
if len(segments) != 1:
751767
if not weak:
@@ -755,7 +771,6 @@ def plot(self, weak: bool = False):
755771
self.clear_plots()
756772

757773
segments_data: list[SegmentDataModel] = segments[0].segments
758-
definition, widget = view.get_current_tab()
759774
plot_segment_data(
760775
widget=widget,
761776
definition=definition,

omc3_gui/segment_by_segment/main_view.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ def update_settings(value: bool, name: str):
144144
if hook is not None:
145145
hook()
146146

147+
qmenu.addSeparator()
147148
for field in fields(settings):
148149
if names is not None and field.name not in names:
149150
continue
@@ -154,9 +155,9 @@ def update_settings(value: bool, name: str):
154155
entry = QtWidgets.QAction(label, self)
155156
entry.setCheckable(True)
156157
entry.setChecked(getattr(settings, field.name))
157-
158158
entry.toggled.connect(partial(update_settings, name=field.name))
159159
qmenu.addAction(entry)
160+
qmenu.addSeparator()
160161

161162
def update_menu_settings(self, menu: str, settings: object, names: Sequence[str] | None = None):
162163
""" Update the menu settings.

omc3_gui/segment_by_segment/plotting.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ def plot_segment_data(widget: DualPlot, definition: ColumnsAndLabels, segments:
2626
Plot the given segments with the given definition.
2727
"""
2828
s_column = S_COLUMN
29+
2930
for plane, plot in zip("xy", [widget.top, widget.bottom]):
3031
data_name = f"{definition.text_label}_{plane}" # coincides with the name in TfsCollection
3132

omc3_gui/segment_by_segment/settings.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from __future__ import annotations
88

99
from pathlib import Path
10-
from dataclasses import dataclass, field, fields
10+
from dataclasses import dataclass, field
1111

1212
from omc3_gui.ui_components.dataclass_ui import metafield
1313

@@ -16,16 +16,17 @@ class MainSettings:
1616
cwd: Path = metafield("Working Directory", "Current working directory. Used for default path when opening file selection dialogs.", default=Path.cwd())
1717
autoload_segments: bool = metafield("Autoload Segments", "Automatically try to load existing segments when loading a measurement.", default=True)
1818
autodefault_segments: bool = metafield("Auto-Add Default Segments", "Automatically add default segments when loading a measurement.", default=False)
19+
suggest_correctors: bool = metafield("Suggest Correctors", "Suggest correctors when editing a new correction file.", default=True)
1920

2021

2122
@dataclass(slots=True)
2223
class PlotSettings:
23-
# connect_x: bool = metafield("Connect X", "Connect X axes.", default=False) # TODO
24-
# connect_y: bool = metafield("Connect Y", "Connect Y axes.", default=False) # TODO
2524
show_legend: bool = metafield("Show Legend", "Show legend.", default=True)
26-
forward: bool = metafield("Forward Propagation", "Show forward propagation.", default=True)
27-
backward: bool = metafield("Backward Propagation", "Show backward propagation.", default=True)
2825
expected: bool = metafield("Expectation", "Show expected value after correction instead of correction itself.", default=False)
26+
forward: bool = metafield("Forward Propagation", "Show forward propagation.", default=True)
27+
backward: bool = metafield("Backward Propagation", "Show backward propagation.", default=False)
28+
connect_x: bool = metafield("Connect X", "Connect X axes.", default=True)
29+
connect_y: bool = metafield("Connect Y", "Connect Y axes.", default=False)
2930

3031

3132
@dataclass(slots=True)

omc3_gui/ui_components/dataclass_ui/controller.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,8 @@ def set_value(value):
376376

377377
else: # Any kind of widget should be able to handle strings.
378378
def get_value():
379+
if not widget.text():
380+
return None
379381
return field_type(widget.text())
380382

381383
def set_value(value):

0 commit comments

Comments
 (0)