Skip to content

Commit 173106d

Browse files
authored
Version 1.3.0 Changes (#104)
1 parent e7065e3 commit 173106d

File tree

14 files changed

+160
-33
lines changed

14 files changed

+160
-33
lines changed

.github/workflows/cron.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
runs-on: ${{ matrix.os }}
1616
strategy:
1717
matrix:
18-
os: [ubuntu-20.04, ubuntu-22.04, macos-latest, windows-latest]
18+
os: [ubuntu-22.04, macos-latest, windows-latest]
1919
python-version: [3.8, 3.9, "3.10", "3.11", 3.x] # crons should always run latest python hence 3.x
2020
# exclude:
2121
# - os: windows-latest # scipy deps issues

.github/workflows/docker.yml

+6-6
Original file line numberDiff line numberDiff line change
@@ -18,32 +18,32 @@ jobs:
1818
steps:
1919

2020
- name: Check Out Repo
21-
uses: actions/checkout@v2
21+
uses: actions/checkout@v3
2222

2323
- name: Set up QEMU
24-
uses: docker/setup-qemu-action@v1
24+
uses: docker/setup-qemu-action@v2
2525

2626
- name: Set up Docker Buildx
2727
id: buildx
28-
uses: docker/setup-buildx-action@v1
28+
uses: docker/setup-buildx-action@v2
2929

3030
- name: Cache Docker layers
31-
uses: actions/cache@v2
31+
uses: actions/cache@v3
3232
with:
3333
path: /tmp/.buildx-cache
3434
key: ${{ runner.os }}-buildx-${{ github.sha }}
3535
restore-keys: |
3636
${{ runner.os }}-buildx-
3737
3838
- name: Login to Docker Hub
39-
uses: docker/login-action@v1
39+
uses: docker/login-action@v2
4040
with:
4141
username: ${{ secrets.DOCKERHUB_ID }}
4242
password: ${{ secrets.DOCKERHUB_TOKEN }}
4343

4444
- name: Build and push image
4545
id: docker_build
46-
uses: docker/build-push-action@v2
46+
uses: docker/build-push-action@v4
4747
with:
4848
context: ./
4949
file: ./docker/Dockerfile

.github/workflows/documentation.yml

+5-5
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
name: ${{ matrix.os }} / ${{ matrix.python-version }}
1717
runs-on: ${{ matrix.os }}
1818
strategy:
19-
matrix: # only lowest supported python on ubuntu-latest
19+
matrix:
2020
os: [ubuntu-latest]
2121
python-version: [3.9]
2222

@@ -65,8 +65,8 @@ jobs:
6565

6666
- name: Upload documentation to gh-pages
6767
if: success() && github.ref == 'refs/heads/master' # only for pushes to master
68-
uses: JamesIves/github-pages-deploy-action@3.7.1
68+
uses: JamesIves/github-pages-deploy-action@v4
6969
with:
70-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
71-
BRANCH: gh-pages
72-
FOLDER: doc_build
70+
folder: doc_build
71+
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Now default
72+
# BRANCH: gh-pages # now default

.github/workflows/tests.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
runs-on: ${{ matrix.os }}
1616
strategy:
1717
matrix:
18-
os: [ubuntu-20.04, ubuntu-22.04, macos-latest, windows-latest]
18+
os: [ubuntu-22.04, macos-latest, windows-latest]
1919
python-version: [3.8, 3.9, "3.10", "3.11"]
2020
fail-fast: false
2121

@@ -41,7 +41,7 @@ jobs:
4141
runs-on: ${{ matrix.os }}
4242
strategy:
4343
matrix:
44-
os: [ubuntu-20.04, ubuntu-22.04, macos-latest, windows-latest]
44+
os: [ubuntu-22.04, macos-latest, windows-latest]
4545
python-version: [3.8, 3.9, "3.10", "3.11"]
4646
fail-fast: false
4747

docs/release.rst

+8
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@ Release Notes
33

44
The full list of releases can be found in the GitHub repository's `releases page <https://github.com/fsoubelet/PyhDToolkit/releases>`_.
55

6+
Version 1.3.0
7+
-------------
8+
9+
.. toctree::
10+
:maxdepth: 2
11+
12+
releases/v1.3.0
13+
614
Version 1.2.0
715
-------------
816

docs/releases/v1.3.0.rst

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
.. _release_1.3.0:
2+
3+
1.3.0
4+
-----
5+
6+
Release `1.3.0` brings a few additions and bug fixes.
7+
8+
Enhancements
9+
~~~~~~~~~~~~
10+
11+
* The `pyhdtoolkit.plotting.aperture.plot_physical_apertures` now has an ``xoffset`` argument similar to the one of the other plotting functions.
12+
* The `pyhdtoolkit.plotting.envelope.plot_beam_envelope` now has an ``xoffset`` argument similar to the one of the other plotting functions.
13+
* The `pyhdtoolkit.plotting.layout` module has a new public function, `scale_patches`, to enable easy scaling of the element patches.
14+
15+
Bug Fixes
16+
~~~~~~~~~
17+
18+
* The `pyhdtoolkit.plotting.layout.plot_machine_layout` function will now plot skew elements too, with a hatching pattern to differentiate them from their normal counterparts.
19+
20+
Maintenance
21+
~~~~~~~~~~~
22+
23+
* The `pyhdtoolkit.plotting.styles.paper.SINGLE_COLUMN` matplotlib style has been adjusted to be tighter at the edges of the figure when saving to a file.
24+
* Relaxed the tolerance of some coupling correction tests as the routine seems to perform slightly worse on the new MAD-X version.
25+
* Removed deprecated workers versions from the CI configuration.
26+
* Updated the CI configuration to use the latest versions of the docker actions.
27+
28+
See `v1.3.0 release notes on GitHub <https://github.com/fsoubelet/PyhDToolkit/releases/tag/1.3.0>`_ and the `full changes since v1.2.0 <https://github.com/fsoubelet/PyhDToolkit/compare/1.2.0...1.3.0>`_.

pyhdtoolkit/plotting/aperture.py

+27-8
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,13 @@ def plot_aperture(
188188

189189

190190
def plot_physical_apertures(
191-
madx, /, plane: str, scale: float = 1, xlimits: Tuple[float, float] = None, **kwargs
191+
madx,
192+
/,
193+
plane: str,
194+
scale: float = 1,
195+
xoffset: float = 0,
196+
xlimits: Tuple[float, float] = None,
197+
**kwargs,
192198
) -> None:
193199
"""
194200
.. versionadded:: 1.2.0
@@ -213,6 +219,11 @@ def plot_physical_apertures(
213219
scale (float): a scaling factor to apply to the beam orbit and beam
214220
enveloppe, for the user to adjust to their wanted scale. Defaults
215221
to 1 (values in [m]).
222+
xoffset (float): An offset applied to the ``S`` coordinate before
223+
plotting. This is useful if you want to center a plot around a
224+
specific point or element, which would then become located
225+
at :math:`s = 0`. Beware this offset is applied before applying
226+
the *xlimits*. Defaults to 0.
216227
xlimits (Tuple[float, float]): will implement xlim (for the ``s``
217228
coordinate) if this is not ``None``, using the tuple passed.
218229
Defaults to ``None``.
@@ -249,10 +260,9 @@ def plot_physical_apertures(
249260
logger.debug("Plotting real element apertures")
250261
axis, kwargs = maybe_get_ax(**kwargs)
251262

252-
if xlimits is not None:
253-
axis.set_xlim(xlimits)
254-
255-
positions, apertures = _get_positions_and_real_apertures(madx, plane, xlimits, **kwargs)
263+
positions, apertures = _get_positions_and_real_apertures(madx, plane, **kwargs)
264+
logger.trace(f"Applying scale ({scale}) and offset ({xoffset})")
265+
positions = positions - xoffset
256266
apertures = apertures * scale
257267

258268
logger.trace("Plotting apertures")
@@ -262,12 +272,16 @@ def plot_physical_apertures(
262272
axis.plot(positions, apertures, "k", label="_nolegend_")
263273
axis.plot(positions, -1 * apertures, "k", label="_nolegend_")
264274

275+
if xlimits:
276+
logger.trace("Setting xlim for longitudinal coordinate")
277+
axis.set_xlim(xlimits)
278+
265279

266280
# ----- Helpers ----- #
267281

268282

269283
def _get_positions_and_real_apertures(
270-
madx, /, plane: str, xlimits: Tuple[float, float] = None, **kwargs
284+
madx, /, plane: str, xoffset: float = 0, xlimits: Tuple[float, float] = None, **kwargs
271285
) -> Tuple[np.ndarray, np.ndarray]:
272286
"""
273287
.. versionadded:: 1.2.0
@@ -288,6 +302,11 @@ def _get_positions_and_real_apertures(
288302
Positional only.
289303
plane (str): the physical plane to plot for, should be either `x`,
290304
`horizontal`, `y` or `vertical`, and is case-insensitive.
305+
xoffset (float): An offset applied to the ``S`` coordinate before
306+
plotting. This is useful if you want to center a plot around a
307+
specific point or element, which would then become located
308+
at :math:`s = 0`. Beware this offset is applied before applying
309+
the *xlimits*. Defaults to 0.
291310
xlimits (Tuple[float, float]): will implement xlim (for the ``s``
292311
coordinate) if this is not ``None``, using the tuple passed.
293312
Defaults to ``None``.
@@ -303,6 +322,7 @@ def _get_positions_and_real_apertures(
303322
madx.command.select(flag="twiss", column=["aper_1", "aper_2"]) # make sure we to get these two
304323
twiss_df = madx.twiss(**kwargs).dframe()
305324
madx.command.select(flag="twiss", clear=True) # clean up
325+
twiss_df.s = twiss_df.s - xoffset
306326

307327
logger.trace("Determining aperture column to use")
308328
plane_number = 1 if plane.lower() in ("x", "horizontal") else 2
@@ -325,7 +345,7 @@ def _get_positions_and_real_apertures(
325345
indices = list(reversed(indices))
326346

327347
logger.trace("Extrapolating data at beginning of elements")
328-
counter = 0# Keep track of exact position in new array with counter
348+
counter = 0 # Keep track of exact position in new array with counter
329349
for j in indices:
330350
new_pos.insert(j + counter, (twiss_df.s[j] - twiss_df.l[j]))
331351
counter += 1
@@ -334,5 +354,4 @@ def _get_positions_and_real_apertures(
334354
apertures = np.array(new_aper)
335355
apertures[apertures == 0] = np.nan
336356
positions = np.array(new_pos)
337-
338357
return positions, apertures

pyhdtoolkit/plotting/envelope.py

+8
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ def plot_beam_envelope(
2323
plane: str,
2424
nsigma: float = 1,
2525
scale: float = 1,
26+
xoffset: float = 0,
2627
xlimits: Tuple[float, float] = None,
2728
**kwargs,
2829
) -> None:
@@ -48,6 +49,11 @@ def plot_beam_envelope(
4849
scale (float): a scaling factor to apply to the beam orbit and beam
4950
enveloppe, for the user to adjust to their wanted scale. Defaults
5051
to 1 (values in [m]).
52+
xoffset (float): An offset applied to the ``S`` coordinate before
53+
plotting. This is useful if you want to center a plot around a
54+
specific point or element, which would then become located
55+
at :math:`s = 0`. Beware this offset is applied before applying
56+
the *xlimits*. Defaults to 0.
5157
xlimits (Tuple[float, float]): will implement xlim (for the ``s``
5258
coordinate) if this is not ``None``, using the tuple passed.
5359
Defaults to ``None``.
@@ -87,6 +93,8 @@ def plot_beam_envelope(
8793
logger.debug("Getting Twiss dframe from MAD-X")
8894
plane_letter = "x" if plane.lower() in ("x", "horizontal") else "y"
8995
twiss_df = madx.twiss(**kwargs).dframe()
96+
twiss_df.s = twiss_df.s - xoffset
97+
9098
if xlimits is not None:
9199
axis.set_xlim(xlimits)
92100
twiss_df = twiss_df[twiss_df.s.between(*xlimits)]

pyhdtoolkit/plotting/layout.py

+43-6
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import matplotlib
1313
import matplotlib.axes
1414
import matplotlib.patches as patches
15+
import numpy as np
1516
import pandas as pd
1617

1718
from cpymad.madx import Madx
@@ -172,7 +173,8 @@ def plot_machine_layout(
172173
dipole_patches_axis = axis.twinx()
173174
dipole_patches_axis.set_ylabel("$\\theta=K_{0}L$ $[rad]$", color="royalblue") # dipoles in blue
174175
dipole_patches_axis.tick_params(axis="y", labelcolor="royalblue")
175-
dipole_patches_axis.set_ylim(k0l_lim)
176+
if not np.nan in k0l_lim:
177+
dipole_patches_axis.set_ylim(k0l_lim)
176178
dipole_patches_axis.grid(False)
177179

178180
if plot_dipoles: # beware 'sbend' and 'rbend' have an 'angle' value and not a 'k0l'
@@ -210,12 +212,14 @@ def plot_machine_layout(
210212
plotted_elements = 0
211213
for quadrupole_name, quadrupole in quadrupoles_df.iterrows():
212214
logger.trace(f"Plotting quadrupole element '{quadrupole_name}'")
215+
element_k = quadrupole.k1l if quadrupole.k1l != 0 else quadrupole.k1sl # can be skew quadrupole
213216
_plot_lattice_series(
214217
axis,
215218
quadrupole,
216-
height=quadrupole.k1l,
217-
v_offset=quadrupole.k1l / 2,
219+
height=element_k,
220+
v_offset=element_k / 2,
218221
color="r",
222+
hatch=None if quadrupole.k1l != 0 else "///", # hatch skew quadrupoles
219223
label="MQ" if plotted_elements == 0 else None, # avoid duplicating legend labels
220224
**kwargs,
221225
)
@@ -235,12 +239,14 @@ def plot_machine_layout(
235239
plotted_elements = 0
236240
for sextupole_name, sextupole in sextupoles_df.iterrows():
237241
logger.trace(f"Plotting sextupole element '{sextupole_name}'")
242+
element_k = sextupole.k2l if sextupole.k2l != 0 else sextupole.k2sl # can be skew sextupole
238243
_plot_lattice_series(
239244
sextupoles_patches_axis,
240245
sextupole,
241-
height=sextupole.k2l,
242-
v_offset=sextupole.k2l / 2,
246+
height=element_k,
247+
v_offset=element_k / 2,
243248
color="goldenrod",
249+
hatch=None if sextupole.k2l != 0 else "\\\\\\", # hatch skew sextupoles
244250
label="MS" if plotted_elements == 0 else None, # avoid duplicating legend labels
245251
**kwargs,
246252
)
@@ -263,12 +269,14 @@ def plot_machine_layout(
263269
plotted_elements = 0
264270
for octupole_name, octupole in octupoles_df.iterrows():
265271
logger.trace(f"Plotting octupole element '{octupole_name}'")
272+
element_k = octupole.k3l if octupole.k3l else octupole.k3sl # can be skew octupole
266273
_plot_lattice_series(
267274
octupoles_patches_axis,
268275
octupole,
269276
height=octupole.k3l,
270277
v_offset=octupole.k3l / 2,
271278
color="forestgreen",
279+
hatch=None if octupole.k3l != 0 else "xxx", # hatch skew octupoles
272280
label="MO" if plotted_elements == 0 else None, # avoid duplicating legend labels
273281
**kwargs,
274282
)
@@ -314,6 +322,35 @@ def plot_machine_layout(
314322
bpm_patches_axis.grid(False)
315323

316324

325+
def scale_patches(scale: float, ylabel: str, **kwargs) -> None:
326+
"""
327+
.. versionadded:: 1.3.0
328+
329+
This is a convenience function to update the scale of the elements layout
330+
patches as well as the corresponding y-axis label.
331+
332+
Args:
333+
scale (float): the scale factor to apply to the patches. The new
334+
height of the patches will be ``scale * original_height``.
335+
ylabel (str): the new label for the y-axis.
336+
**kwargs: If either `ax` or `axis` is found in the kwargs, the
337+
corresponding value is used as the axis object to plot on,
338+
otherwise the current axis is used.
339+
340+
Example:
341+
.. code-block:: python
342+
343+
>>> fig, ax = plt.subplots(figsize=(6, 2))
344+
>>> plot_machine_layout(madx, title="Machine Elements", lw=3)
345+
>>> scale_patches(ax=fig.axes[0], scale=100, ylabel=r"$K_{1}L$ $[10^{-2} m^{-1}]$")
346+
"""
347+
axis, kwargs = maybe_get_ax(**kwargs)
348+
axis.set_ylabel(ylabel)
349+
for patch in axis.patches:
350+
h = patch.get_height()
351+
patch.set_height(scale * h)
352+
353+
317354
# ----- Helpers ----- #
318355

319356

@@ -399,7 +436,7 @@ def _determine_default_knl_lim(df: pd.DataFrame, col: str, coeff: float) -> Tupl
399436
400437
Determine the default limits for the ``knl`` axis, when plotting machine
401438
layout. This is in case `None` are provided by the user, to make sure the
402-
plot still looks coherent and symmetric in
439+
plot still looks coherent and symmetric in
403440
`~.plotting.utils.plot_machine_layout`.
404441
405442
The limits are determined symmetric, using the maximum absolute value of

pyhdtoolkit/plotting/styles/paper.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@
5959
"figure.figsize": (11, 7), # Size of the figure
6060
"figure.titlesize": 20, # Size of the figure title
6161
"figure.subplot.left": 0.13, # Left side limit of the subplots of the figure
62-
"figure.subplot.top": 0.92, # Top side limit of the subplots of the figure
63-
"figure.subplot.bottom": 0.15, # Bottom side limit of the subplots of the figure
62+
"figure.subplot.top": 0.9, # Top side limit of the subplots of the figure
63+
"figure.subplot.bottom": 0.1, # Bottom side limit of the subplots of the figure
6464
# ------ Saving ------ #
6565
"savefig.dpi": 400, # Saved figure dots per inch
6666
"savefig.format": "pdf", # Saved figure file format

pyhdtoolkit/version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
VERSION = "1.2.0"
1+
VERSION = "1.3.0"
22

33

44
def version_info() -> str:

0 commit comments

Comments
 (0)