Skip to content

Commit 19304b8

Browse files
committed
Fixing some bugs, check segment start
1 parent 41b9665 commit 19304b8

File tree

14 files changed

+127
-97
lines changed

14 files changed

+127
-97
lines changed

omc3_gui/plotting/classes.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ def plots(self) -> tuple[pg.PlotWidget, pg.PlotWidget]:
4343
def clear(self) -> None:
4444
for plot in self.plots:
4545
plot.clear()
46+
plot.enableAutoRange()
4647

4748
def set_connect_x(self, connect: bool) -> None:
4849
if connect:

omc3_gui/plotting/tfs_plotter.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def plot_dataframes(
3434
legend: bool = True,
3535
brightness: int | None = None,
3636
marker: str = 'o',
37+
markersize: float = 6,
3738
linestyle: PenStyle = PenStyle.SolidLine,
3839
suffix: str = "",
3940
):
@@ -52,6 +53,7 @@ def plot_dataframes(
5253
legend (bool, optional): Whether to add a legend to the plot. Defaults to True.
5354
brightness (int, optional): The brightness of the colors to use. Defaults to None.
5455
marker (str, optional): The marker to use for the data points. Defaults to 'o'.
56+
markersize (float, optional): The size of the markers to use for the data points. Defaults to 6.
5557
linestyle (PenStyle, optional): The linestyle to use for the data points. Defaults to PenStyle.SolidLine.
5658
suffix (str, optional): The suffix to add to the legend. Defaults to "".
5759
"""
@@ -80,6 +82,7 @@ def plot_dataframes(
8082
label=f"{name}{suffix}",
8183
color=color,
8284
marker=marker,
85+
markersize=markersize,
8386
linestyle=linestyle,
8487
)
8588

@@ -90,7 +93,8 @@ def plot_dataframes(
9093
plot_item.setLabel("left", ylabel)
9194

9295
plot_item.legend.setVisible(legend)
93-
96+
97+
9498
def plot_errorbar(
9599
plot: pg.PlotItem,
96100
*,
@@ -102,7 +106,7 @@ def plot_errorbar(
102106
label: str | None = None,
103107
color: str | pg.Color | None = None,
104108
marker: str = 'o',
105-
markersize: int = 6,
109+
markersize: float = 6,
106110
linestyle: PenStyle = PenStyle.SolidLine,
107111
linewidth: float = 2,
108112
) -> tuple[pg.PlotDataItem, pg.ErrorBarItem]:
@@ -121,8 +125,9 @@ def plot_errorbar(
121125
label (str | None, optional): The label of the errorbar. Defaults to None.
122126
color (str | None, optional): The color of the errorbar. Defaults to None.
123127
marker (str, optional): The marker of the errorbar. Defaults to 'o'.
124-
markersize (int, optional): The markersize of the errorbar. Defaults to 10.
128+
markersize (float, optional): The markersize of the errorbar. Defaults to 10.
125129
linestyle (PenStyle, optional): The linestyle of the errorbar. Defaults to PenStyle.SolidLine.
130+
linewidth (float, optional): The linewidth of the errorbar. Defaults to 2.
126131
"""
127132

128133
curvePen = pg.mkPen(color=color, width=linewidth, style=linestyle)

omc3_gui/sbs_gui.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
"""
2+
Segment-by-Segment GUI
3+
----------------------
4+
5+
Graphical user interface to run the Segment-by-Segment propagation.
6+
"""
7+
import sys
8+
from omc3_gui.segment_by_segment.main_controller import SbSController
9+
from omc3_gui.utils.log_handler import init_logging
10+
11+
# --- For QT Debugging ----------------
12+
# import os
13+
# os.environ["QT_DEBUG_PLUGINS"] = "1"
14+
# -------------------------------------
15+
16+
if __name__ == "__main__":
17+
init_logging()
18+
sys.exit(SbSController.run_application())

omc3_gui/segment_by_segment.py

Lines changed: 0 additions & 36 deletions
This file was deleted.

omc3_gui/segment_by_segment/defaults.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,10 @@
3333
"kq6.{}{}b{}",
3434
"kq5.{}{}b{}",
3535
"kq4.{}{}b{}",
36-
"kqx.{}{}b{}",
37-
"kqsx3.{}{}b{}",
38-
"ktqx2.{}{}b{}",
39-
"ktqx1.{}{}b{}",
40-
"kqx.{}{}b{}",
36+
"kqsx3.{}{}",
37+
"ktqx2.{}{}",
38+
"ktqx1.{}{}",
39+
"kqx.{}{}",
4140
)
4241

4342
def get_default_correctors(measurement: OpticsMeasurement) -> str:

omc3_gui/segment_by_segment/main_controller.py

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import logging
1010
from functools import partial
1111
from pathlib import Path
12+
import re
1213
from typing import TYPE_CHECKING
1314

1415
from omc3.sbs_propagation import segment_by_segment
@@ -71,7 +72,7 @@ def connect_signals(self):
7172
view.add_settings_to_menu(
7273
menu="View",
7374
settings=self.settings.plotting,
74-
hook=partial(self.plot, weak=True), # update plots if possible
75+
hook=partial(self.plot, fail_ok=True), # update plots if possible
7576
)
7677

7778
# Measurements -------------------------------------------------------------
@@ -488,10 +489,6 @@ def segment_selection_changed(self, segments: Sequence[SegmentItemModel] | None
488489
return
489490

490491
self.set_segment_interaction_buttons_enabled(True)
491-
if len(segments) > 1:
492-
LOGGER.debug("More than one segment selected. Clearing Plots.")
493-
return
494-
495492
self.plot()
496493

497494
@Slot()
@@ -524,7 +521,8 @@ def add_default_segements_to_measurement(self, measurement: OpticsMeasurement):
524521
segment = SegmentDataModel(measurement, *segment_tuple)
525522
segment.start = f"{segment.start}.B{measurement.beam}"
526523
segment.end = f"{segment.end}.B{measurement.beam}"
527-
measurement.try_add_segment(segment)
524+
measurement.try_add_segment(segment, silent=True)
525+
return
528526

529527
# TODO: Implement for other accelerators
530528
LOGGER.error(f"No beam found in measurement {measurement.display()}. Cannot add default segments.")
@@ -543,6 +541,7 @@ def new_segment(self):
543541

544542
LOGGER.debug("Opening edit dialog for a new segment.")
545543
dialog = SegmentDialog(parent=view)
544+
dialog.validate_only_modified = False
546545
if dialog.exec_() == dialog.Rejected:
547546
LOGGER.debug("Segment dialog cancelled.")
548547
return
@@ -579,7 +578,7 @@ def copy_segment(self, segments: Sequence[SegmentItemModel] | None = None):
579578
return
580579

581580
for segment_item in segments:
582-
new_segment_name = f"{segment_item.name} - Copy"
581+
new_segment_name = f"{segment_item.name}_copy"
583582
for measurement in selected_measurements:
584583
# Check if copied segment name already exists in one of the measurements
585584
try:
@@ -597,6 +596,7 @@ def copy_segment(self, segments: Sequence[SegmentItemModel] | None = None):
597596
for segment in segment_item.segments:
598597
new_segment = segment.copy()
599598
new_segment.name = new_segment_name
599+
new_segment.measurement = measurement
600600
measurement.try_add_segment(new_segment)
601601

602602
self.measurement_selection_changed(selected_measurements)
@@ -619,16 +619,12 @@ def remove_segment(self, segments: Sequence[SegmentItemModel] | None = None):
619619
return
620620

621621
LOGGER.debug(f"Removing {len(segments)} segments.")
622-
selected_measurements = view.get_selected_measurements()
623-
if not selected_measurements:
624-
LOGGER.error("Please select at least one measurement.")
625-
return
626622

627-
for measurement in selected_measurements:
628-
for segment_item in segments:
629-
measurement.try_remove_segment(segment_item.name)
630-
631-
self.measurement_selection_changed(selected_measurements)
623+
for segment_item in segments:
624+
for segment_data in segment_item.segments:
625+
segment_data.measurement.remove_segment(segment_data)
626+
627+
self.measurement_selection_changed(view.get_selected_measurements())
632628

633629
@Slot()
634630
def load_segments(self):
@@ -749,7 +745,7 @@ def clear_all():
749745
# -------------------------------------
750746

751747
# Plotting ---------------------------------------------------------------------
752-
def plot(self, weak: bool = False):
748+
def plot(self, fail_ok: bool = False):
753749
""" Trigger a plot update with the currently selected segments. """
754750
view: SbSWindow = self._view
755751
settings: PlotSettings = self.settings.plotting
@@ -763,14 +759,27 @@ def plot(self, weak: bool = False):
763759
widget.set_connect_y(settings.connect_y)
764760

765761
segments = view.get_selected_segments()
766-
if len(segments) != 1:
767-
if not weak:
762+
if not len(segments):
763+
if not fail_ok:
768764
LOGGER.error("Please select exactly one segment to plot.")
769765
return
770766

771-
self.clear_plots()
767+
768+
segments_data: list[SegmentDataModel] = [s_data for s in segments for s_data in s.segments if s_data.has_run()]
769+
if not len(segments_data):
770+
if not fail_ok:
771+
LOGGER.error("Please run at least one segment before plotting.")
772+
return
773+
774+
if settings.same_start:
775+
starts = {re.sub(r"\.B[12]$", "", s.start, flags=re.IGNORECASE) for s in segments_data}
776+
if len(starts) > 1:
777+
if not fail_ok:
778+
LOGGER.error("Please select segments with the same starting element.")
779+
return
772780

773-
segments_data: list[SegmentDataModel] = segments[0].segments
781+
self.clear_plots()
782+
774783
plot_segment_data(
775784
widget=widget,
776785
definition=definition,
@@ -795,5 +804,5 @@ def show_settings(self):
795804
menu="View",
796805
settings=self.settings.plotting,
797806
)
798-
self.plot(weak=True)
807+
self.plot(fail_ok=True)
799808

omc3_gui/segment_by_segment/main_view.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,10 +151,15 @@ def update_settings(value: bool, name: str):
151151

152152
if field.name.startswith("_"):
153153
continue
154+
155+
value = getattr(settings, field.name)
156+
if not isinstance(value, bool):
157+
continue
158+
154159
label = field.metadata.get("label", field.name)
155160
entry = QtWidgets.QAction(label, self)
156161
entry.setCheckable(True)
157-
entry.setChecked(getattr(settings, field.name))
162+
entry.setChecked(value)
158163
entry.toggled.connect(partial(update_settings, name=field.name))
159164
qmenu.addAction(entry)
160165
qmenu.addSeparator()
@@ -179,6 +184,9 @@ def update_menu_settings(self, menu: str, settings: object, names: Sequence[str]
179184

180185
label = field.metadata.get("label", field.name)
181186
entry: QtWidgets.QAction = self.get_action_by_title(label, parent=qmenu)
187+
if entry is None:
188+
continue
189+
182190
entry.setChecked(getattr(settings, field.name))
183191

184192
def _build_gui(self):

omc3_gui/segment_by_segment/measurement_model.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,24 @@
3232
DATE: str = "DATE"
3333

3434
FILES_TO_LOOK_FOR: tuple[str, ...] = tuple(f"{name}{plane}" for name in (KICK_NAME, PHASE_NAME, BETA_NAME) for plane in ("x", "y"))
35+
TO_BE_DEFINED: str = "to_be_defined"
3536

3637
LOGGER = logging.getLogger(__name__)
3738

3839

40+
def exists(value: Path | None) -> bool:
41+
return value is not None and value.exists()
42+
43+
3944
@dataclass(slots=True)
4045
class OpticsMeasurement:
4146
""" Class to load and hold the optics-measurement folder.
4247
This class also stores the meta-data for the loaded measurement,
4348
which can then be passed on to the segment-by-segment.
4449
The :func:`omc3_gui.utils.dataclass_ui.metafield` is used to provide hints about the fields for the GUI.
4550
"""
46-
measurement_dir: DirectoryPath = metafield("Optics Measurement", "Path to the optics-measurement folder")
47-
model_dir: DirectoryPath = metafield("Model", "Path to the model folder", default=None)
51+
measurement_dir: DirectoryPath = metafield("Optics Measurement", "Path to the optics-measurement folder", default=Path(TO_BE_DEFINED), validate=exists)
52+
model_dir: DirectoryPath = metafield("Model", "Path to the model folder", default=Path(TO_BE_DEFINED), validate=exists)
4853
accel: str = metafield("Accelerator", "Name of the accelerator", default=None)
4954
output_dir: DirectoryPath = metafield("Output", "Path to the sbs-output folder", default=None)
5055
corrections: FilePath = metafield("Corrections", "Path to the corrections file", default=None)
@@ -114,11 +119,14 @@ def add_segment(self, segment: SegmentDataModel):
114119

115120
self.segments.append(segment)
116121

117-
def try_add_segment(self, segment: SegmentDataModel) -> bool:
122+
def try_add_segment(self, segment: SegmentDataModel, silent: bool = False) -> bool:
118123
try:
119124
self.add_segment(segment)
120125
except NameError as e:
121-
LOGGER.error(str(e))
126+
if silent:
127+
LOGGER.debug(str(e))
128+
else:
129+
LOGGER.error(str(e))
122130
return False
123131
return True
124132

omc3_gui/segment_by_segment/measurement_view.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,10 @@
55
This module contains the view for the measurement dialog.
66
"""
77
from dataclasses import fields
8-
from pathlib import Path
98

109
from omc3_gui.segment_by_segment.measurement_model import OpticsMeasurement
1110
from omc3_gui.ui_components.dataclass_ui import DataClassDialog, FieldUIDef, DataClassUI
1211

13-
TO_BE_DEFINED = Path("to_be_defined")
1412

1513

1614
class OpticsMeasurementDialog(DataClassDialog):
@@ -20,7 +18,7 @@ class OpticsMeasurementDialog(DataClassDialog):
2018

2119
def __init__(self, parent=None, optics_measurement: OpticsMeasurement | None = None):
2220
if optics_measurement is None:
23-
optics_measurement = OpticsMeasurement(measurement_dir=TO_BE_DEFINED, output_dir=TO_BE_DEFINED)
21+
optics_measurement = OpticsMeasurement()
2422

2523
non_editable = ("measurement_dir", ) # set by program not by user
2624
dataclass_ui = DataClassUI(

0 commit comments

Comments
 (0)