Skip to content

Commit c929e01

Browse files
authored
Plot normalized dispersion (#426)
* extra plotting for normalized dispersion * updated changelog and version * added test
1 parent 41f367c commit c929e01

File tree

6 files changed

+761
-56
lines changed

6 files changed

+761
-56
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# OMC3 Changelog
22

3+
#### 2023-09-01 - v0.11.2 - _jdilly_
4+
5+
- Fixed:
6+
- Plot Optics: making normalized dispersion plot a special case.
7+
8+
- Added:
9+
- Plot Optics: optional input "--labels" to manually set the legend-labels.
10+
311
#### 2023-06-16 - v0.11.1 - _jdilly_
412

513
- Fixed:

omc3/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
__title__ = "omc3"
1212
__description__ = "An accelerator physics tools package for the OMC team at CERN."
1313
__url__ = "https://github.com/pylhc/omc3"
14-
__version__ = "0.11.1"
14+
__version__ = "0.11.2"
1515
__author__ = "pylhc"
1616
__author_email__ = "[email protected]"
1717
__license__ = "MIT"

omc3/plotting/plot_optics_measurements.py

Lines changed: 185 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
1111
figs = plot(
1212
folders=['folder1', 'folder2'],
13+
labels=['LabelForFolder1', 'LabelForFolder2'],
1314
combine_by=['files'], # to compare folder1 and folder2
1415
output='output_directory',
1516
delta=True, # delta from reference
@@ -27,68 +28,146 @@
2728
2829
*--Required--*
2930
30-
- **folders** *(MultiClass)*: Optics Measurements folders containing the analysed data.
31+
- **folders** *(PathOrStr)*:
3132
32-
- **optics_parameters** *(str)*: Optics parameters to plot, e.g. 'beta_amplitude'.
33-
RDTs need to be specified with plane, e.g. 'f1001_x'
33+
Optics Measurements folders containing the analysed data.
34+
35+
36+
- **optics_parameters** *(str)*:
37+
38+
Optics parameters to plot, e.g. 'beta_amplitude'. RDTs need to be
39+
specified with plane, e.g. 'f1001_x'
3440
3541
3642
*--Optional--*
3743
38-
- **change_marker**: Changes marker for each line in the plot.
44+
- **change_marker**:
45+
46+
Changes marker for each line in the plot.
47+
48+
action: ``store_true``
49+
50+
51+
- **combine_by**:
52+
53+
Combine plots into one. Either files, planes (not separated into two
54+
axes) or both.
55+
56+
choices: ``['files', 'planes']``
57+
58+
59+
- **delta**:
60+
61+
Plot the difference to model instead of the parameter.
62+
63+
action: ``store_true``
64+
65+
66+
- **errorbar_alpha** *(float)*:
67+
68+
Alpha value for error bars
69+
70+
default: ``0.6``
71+
72+
73+
- **ip_positions**:
74+
75+
Input to plot IP-Positions into the plots. Either 'LHCB1' or 'LHCB2'
76+
for LHC defaults, a dictionary of labels and positions or path to TFS
77+
file of a model.
78+
79+
80+
- **ip_search_pattern**:
81+
82+
In case your IPs have a weird name. Specify regex pattern.
83+
84+
default: ``IP\\d$``
85+
86+
87+
- **labels** *(str)*:
88+
89+
Labels for the folders. If not provided, the folder names (with
90+
parents until each label is unique) will be used.
91+
92+
93+
- **lines_manual** *(DictAsString)*:
94+
95+
List of manual lines to plot. Need to contain arguments for axvline,
96+
and may contain the additional keys "text" and "loc" which is one of
97+
['bottom', 'top', 'line bottom', 'line top'] and places the text at
98+
the given location.
99+
100+
default: ``[]``
101+
102+
103+
- **manual_style** *(DictAsString)*:
104+
105+
Additional style rcParameters which update the set of predefined ones.
106+
107+
default: ``{}``
108+
109+
110+
- **ncol_legend** *(int)*:
111+
112+
Number of bpm legend-columns. If < 1 no legend is shown.
113+
114+
default: ``3``
115+
116+
117+
- **output** *(PathOrStr)*:
118+
119+
Folder to output the results to.
120+
121+
122+
- **plot_styles** *(str)*:
39123
40-
Action: ``store_true``
41-
- **combine_by**: Combine plots into one. Either files, planes (not separated into two axes) or both.
124+
Which plotting styles to use, either from plotting.styles.*.mplstyles
125+
or default mpl.
42126
43-
Choices: ``['files', 'planes']``
44-
- **delta**: Plot the difference to model instead of the parameter.
127+
default: ``['standard']``
45128
46-
Action: ``store_true``
47-
- **errorbar_alpha** *(float)*: Alpha value for error bars
48129
49-
Default: ``0.6``
50-
- **ip_positions**: Input to plot IP-Positions into the plots. Either 'LHCB1'
51-
or 'LHCB2' for LHC defaults, a dictionary of labels and positions or path to TFS file of a model.
130+
- **share_xaxis**:
52131
53-
- **ip_search_pattern**: In case your IPs have a weird name. Specify regex pattern.
132+
In case of multiple axes per figure, share x-axis.
54133
55-
Default: ``IP\\d$``
56-
- **lines_manual** *(DictAsString)*: List of manual lines to plot.
57-
Need to contain arguments for axvline, and may contain the additional keys "text"
58-
and "loc" which is one of ['bottom', 'top', 'line bottom', 'line top']
59-
and places the text at the given location.
134+
action: ``store_true``
60135
61-
Default: ``[]``
62-
- **manual_style** *(DictAsString)*: Additional style rcParameters which
63-
update the set of predefined ones.
64136
65-
Default: ``{}``
66-
- **ncol_legend** *(int)*: Number of bpm legend-columns. If < 1 no legend is shown.
137+
- **show**:
67138
68-
Default: ``3``
69-
- **output** *(MultiClass)*: Folder to output the results to.
139+
Shows plots.
70140
71-
- **plot_styles** *(str)*: Which plotting styles to use,
72-
either from plotting.styles.*.mplstyles or default mpl.
141+
action: ``store_true``
73142
74-
Default: ``['standard']``
75-
- **share_xaxis**: In case of multiple axes per figure, share x-axis.
76143
77-
Action: ``store_true``
78-
- **show**: Shows plots.
144+
- **suppress_column_legend**:
79145
80-
Action: ``store_true``
81-
- **suppress_column_legend**: Does not show column name in legend
82-
e.g. when combining by files (see also `ncol_legend`).
146+
Does not show column name in legend e.g. when combining by files (see
147+
also `ncol_legend`).
83148
84-
Action: ``store_true``
85-
- **x_axis**: Which parameter to use for the x axis.
149+
action: ``store_true``
150+
151+
152+
- **x_axis**:
153+
154+
Which parameter to use for the x axis.
155+
156+
choices: ``['location', 'phase-advance']``
157+
158+
default: ``location``
159+
160+
161+
- **x_lim** *(OptionalFloat)*:
162+
163+
Limits on the x axis (Tupel)
164+
165+
166+
- **y_lim** *(OptionalFloat)*:
167+
168+
Limits on the y axis (Tupel)
86169
87-
Choices: ``['location', 'phase-advance']``
88-
Default: ``location``
89-
- **x_lim** *(float, int, None)*: Limits on the x axis (Tupel)
90170
91-
- **y_lim** *(float, int, None)*: Limits on the y axis (Tupel)
92171
"""
93172
from pathlib import Path
94173

@@ -97,7 +176,7 @@
97176
from generic_parser.entry_datatypes import DictAsString
98177
from omc3.definitions.constants import PLANES
99178
from omc3.definitions.optics import POSITION_COLUMN_MAPPING, FILE_COLUMN_MAPPING, ColumnsAndLabels, RDT_COLUMN_MAPPING
100-
from omc3.optics_measurements.constants import EXT, AMPLITUDE, PHASE, REAL, IMAG
179+
from omc3.optics_measurements.constants import EXT, AMPLITUDE, NORM_DISP_NAME, PHASE, REAL, IMAG
101180
from omc3.optics_measurements.rdt import _rdt_to_order_and_type
102181
from omc3.plotting.optics_measurements.constants import (DEFAULTS, IP_POS_DEFAULT)
103182
from omc3.plotting.plot_tfs import plot as plot_tfs, OptionalFloat
@@ -127,6 +206,14 @@ def get_params() -> EntryPointParameters:
127206
type=str,
128207
nargs="+",
129208
)
209+
params.add_parameter(
210+
name="labels",
211+
help="Labels for the folders. If not provided, the folder names "
212+
"(with parents until each label is unique) will be used.",
213+
required=False,
214+
nargs="+",
215+
type=str,
216+
)
130217
params.add_parameter(
131218
name="delta",
132219
help="Plot the difference to model instead of the parameter.",
@@ -263,7 +350,10 @@ def plot(opt):
263350

264351
is_rdt = optics_parameter.lower().startswith("f")
265352
files, file_labels = zip(*get_unique_filenames(opt.folders))
266-
file_labels = ["_".join(flabels) for flabels in file_labels]
353+
if opt.labels:
354+
file_labels = opt.labels
355+
else:
356+
file_labels = ["_".join(flabels) for flabels in file_labels]
267357

268358
if is_rdt:
269359
fig_dict.update(_plot_rdt(
@@ -274,14 +364,22 @@ def plot(opt):
274364
if not optics_parameter.endswith("_"):
275365
optics_parameter += "_"
276366

277-
fig_dict.update(_plot_param(
278-
optics_parameter, files, file_labels, x_axis.column, x_axis.label,
279-
ip_positions, opt,)
280-
)
367+
if optics_parameter == NORM_DISP_NAME:
368+
fig_dict.update(_plot_norm_dispersion(
369+
optics_parameter, files, file_labels, x_axis.column, x_axis.label,
370+
ip_positions, opt,)
371+
)
372+
else:
373+
fig_dict.update(_plot_param(
374+
optics_parameter, files, file_labels, x_axis.column, x_axis.label,
375+
ip_positions, opt,)
376+
)
281377
return fig_dict
282378

283379

284380
def _check_opt(opt):
381+
if opt.labels and not len(opt.labels) == len(opt.folders):
382+
raise ValueError("Labels need to be of same size as folders.")
285383
return opt
286384

287385

@@ -371,7 +469,7 @@ def _get_rdt_columns():
371469

372470

373471
def _plot_param(optics_parameter, files, file_labels, x_column, x_label, ip_positions, opt):
374-
"""Main plotting function for all parameters but RDTs."""
472+
"""Main plotting function for all parameters but RDTs and normalized dispersion."""
375473
y_column, error_column, column_label, y_label = _get_columns_and_label(optics_parameter, opt.delta)
376474

377475
same_fig = None
@@ -416,6 +514,45 @@ def _plot_param(optics_parameter, files, file_labels, x_column, x_label, ip_posi
416514
'share_xaxis'])
417515
)
418516

517+
def _plot_norm_dispersion(optics_parameter, files, file_labels, x_column, x_label, ip_positions, opt):
518+
"""Plotting function for normalized dispersion.
519+
Normalized dispersion is special, as we only evaluate the horizontal plane (X) in the optics measurements.
520+
We therefore plot the delta in the second (lower) plot."""
521+
y_column, error_column, column_label, y_label = _get_columns_and_label(optics_parameter, delta=False)
522+
delta_y_column, delta_error_column, delta_column_label, delta_y_label = _get_columns_and_label(optics_parameter, delta=True)
523+
524+
same_fig = None
525+
column_labels = [column_label, delta_column_label]
526+
same_fig = 'columns'
527+
528+
if opt.suppress_column_legend:
529+
column_labels = ['']
530+
531+
prefix = ''
532+
if opt.combine_by and "files" in opt.combine_by:
533+
prefix += f'{optics_parameter}'
534+
535+
return plot_tfs(
536+
files=[f.absolute()/f'{optics_parameter}{{0}}{EXT}' for f in files],
537+
file_labels=list(file_labels),
538+
y_columns=[y_column, delta_y_column],
539+
y_labels=[[y_label, delta_y_label]],
540+
column_labels=column_labels,
541+
error_columns=[error_column, delta_error_column],
542+
x_columns=[x_column, x_column],
543+
x_labels=[x_label, x_label],
544+
planes=[PLANES[0]],
545+
vertical_lines=ip_positions + opt.lines_manual,
546+
same_figure=same_fig,
547+
same_axes=opt.combine_by,
548+
single_legend=True,
549+
output_prefix=f"plot_{prefix}",
550+
**opt.get_subdict(['show', 'output',
551+
'plot_styles', 'manual_style',
552+
'change_marker', 'errorbar_alpha',
553+
'ncol_legend', 'x_lim', 'y_lim',
554+
'share_xaxis'])
555+
)
419556

420557
def _get_columns_and_label(parameter, delta):
421558
cal: ColumnsAndLabels = FILE_COLUMN_MAPPING[parameter]

omc3/utils/iotools.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,15 @@
44
55
Helper functions for input/output issues.
66
"""
7-
import sys
8-
from typing import Iterable, Any, Union
9-
10-
import re
11-
12-
import json
137
import os
8+
import re
149
import shutil
10+
import sys
1511
from pathlib import Path
12+
from typing import Any, Union
1613

1714
from generic_parser.entry_datatypes import get_instance_faker_meta, get_multi_class
1815
from generic_parser.entrypoint_parser import save_options_to_config
19-
from pandas import DataFrame
2016
from tfs import TfsDataFrame
2117

2218
from omc3.definitions import formats
@@ -125,6 +121,7 @@ def __new__(cls, value):
125121
"""A class that allows `float`, 'int' or `None`.
126122
Can be used in numeric-lists when individual entries can be `None`."""
127123
OptionalFloat = get_multi_class(float, int, type(None))
124+
OptionalFloat.__name__ = "OptionalFloat"
128125

129126

130127
def strip_quotes(value: Any) -> Any:

0 commit comments

Comments
 (0)