Common concepts#
Show code cell content
%load_ext autoreload
%autoreload 2
from matplotlib import pyplot as plt
import numpy as np
import xplt
np.random.seed(4873153)
xplt.apply_style()
xplt.mpl.rcParams["figure.figsize"] = (3, 2)
Show code cell content
data = xplt.util.AttrDict(
label="Data A",
x=1e-3 * np.random.normal(size=10000),
y=2e-3 * (0.5 + np.random.normal(size=10000)),
)
data2 = xplt.util.AttrDict(
label="Data B",
x=2e-3 + 3 * data.x,
y=data.y / 2 - 3e-3,
)
Creating plots#
All plotting classes share a common API as they are derived either from the base class XPlot
or XManifoldPlot
. In the following we will use the ParticleHistogramPlot
to demonstrate the common concepts.
To quickly create a plot, simply instanciate it and provide the data:
plot = xplt.ParticleHistogramPlot("x", particles=data)

The only mandatory parameter is the property to be plotted ("x"
). Most plots also accept a kind=
parameter to plot different properties on subplots or twin axes.
The data provided must contain or be suited to derive the requested properties. See below for a detailed description of properties, units and labels.
Most plots allso accept a mask=
parameter to consider only a subset of the data:
plot = xplt.ParticleHistogramPlot("x", particles=data, mask=data.x < 1e-3)

Updating plot data#
Plots can also be created blank, and the data updated later. This is very useful to create animations (see Animations):
plot = xplt.ParticleHistogramPlot(
"x", bin_width=1e-4, plot_kwargs=dict(label="Data A")
)
plot.update(data);

The parameter plot_kwargs=
always allows to customize the artist.
You can add more datasets:
plot.add_dataset(
"ref", # optional ID to update data later
particles=data2,
plot_kwargs=dict(label="Data B", c="C2", lw=2),
autoscale=True,
)
plot.fig

…and update them as needed:
plot.update(data2, mask=data2.x > 0, dataset_id="ref")
plot.fig

Tip
To add multiple datasets in a loop, pass add_default_dataset=False
to the constructor to avoid the default artists from being created for you.
The parameter autoscale=
of the xplt.ParticleHistogramPlot.add_dataset()
and xplt.ParticleHistogramPlot.update()
methods allows to specify the autoscale behaviour. By default, autoscaling is only performed on the first time data is supplied to the plot.
You can also manually autoscale the plot anytime:
plot.autoscale(axis="x", tight=False, reset=True)
plot.fig

Composing plots#
By passing an existing axis to the constructor, it is possible to create composed plots (the axis shape must match the one otherwise created by the plot):
xplt.mpl.rcParams["figure.figsize"] = (6.4, 4.8)
fig, axs = plt.subplots(2, 2, sharex="col", sharey="row")
fig.suptitle("A composed plot")
for i, p in enumerate("xy"):
for j, dat in enumerate((data, data2)):
plot = xplt.ParticleHistogramPlot(
p,
dat,
"count,cumulative",
ax=axs[:, i],
plot_kwargs=dict(label=dat.label, ls=f"-{j}"), # customization
)
if i == 0:
break
for a in axs[:, 1]:
a.set(ylabel=None)

Properties, Units and Labels#
Properties are what makes this library easy to use while still very flexible.
A property is anything that we can “get” from a dataset, either as an attribute data.xyz
, an index data["xyz"]
or even a column in a pandas dataframe.
For brevity, consider the following arbitrary dataset in the following:
# custom data
N = 10000
data = {
"h": np.linspace(0, 100, num=N),
"w": np.random.normal(size=N),
"x": np.random.normal(size=N),
"y": np.random.normal(size=N),
}
Now we can plot the x-y-phasespace simply by specifying exactly that:
plot = xplt.PhaseSpacePlot(data, "x-y", display_units=dict(y="m"))

This works, because both x
and y
are standard properties which are defined in the library with default settings for units, labels and symbols.
Here specifically, the assumption is that x
is provided in meters since that is the SI unit used by Xsuite, and that the default display unit for x
should be millimeters. You can specify a display unit, and the data is automatically converted accordingly.
See below for a list of predefined properties and the default assumed. You can add or change properties and their respective units, labels and symbols if required. Futher, derived properties can easily be defined building on the already existing ones.
Adding custom data properties#
To define or overwrite properties of a data object with a certain unit or meaning, you can either register them globally:
# our data["w"] is the width in km
xplt.register_data_property("w", data_unit="km", symbol="$w_x$", description="Width")
Or on-the-fly for a single plot with the data_units
parameter.
Both enable automatic axes and legend labeling, as well as the use of the display_units
parameter:
# our data["h"] is in mm, but we want to convert it to cm
plot = xplt.PhaseSpacePlot(
data, "w-h", data_units={"h": "mm"}, display_units={"h": "cm"}
)

Derived properties#
It is often useful to add properties that depend on already existing ones, e.g. if you simply want to plot the squareroot of a parameter, or have a complex expression. The function parameters must be valid property names, such that the data and units can be inferred automatically. It is also possible to specify the unit explicitly where necessary.
# since both x and y are know properties (in meter), A is known to be in square meter
xplt.register_derived_property("A", lambda x, y: x * y, description="Area")
# since the unit of `6` can not be inferred, we declare B to be in square meter too
xplt.register_derived_property("B", lambda A: A + 6, unit="m^2")
plot = xplt.PhaseSpacePlot(data, "A-w")

Default properties#
Global default properties applicable to all plots:
Show code cell source
from IPython.display import display, Markdown
import pandas
import pint
def get_subclass_names(classname):
all = {classname.__name__: classname}
for subclassname in classname.__subclasses__():
all.update(get_subclass_names(subclassname))
return all
def display_class_info(cls):
md = "Additional default properties applicable only to:"
for name, c in sorted(get_subclass_names(cls).items()):
if name.endswith("Plot") and not ".. deprecated::" in c.__doc__:
md += f" {{class}}`{name} <{c.__module__}.{c.__qualname__}>`\n"
display(Markdown(md))
def display_property_info(properties):
der = np.any(
[isinstance(p, xplt.properties.DerivedProperty) for p in properties.values()]
)
df = pandas.DataFrame(columns=["Unit", "Symbol", "Description", "Derived from"])
df.index.name = "Property"
for p, prop in sorted(properties.items()):
df.loc[f"`{p}`"] = [
f"$ {pint.Unit(prop.unit):~#L} $",
prop.symbol,
prop.description or "",
(
f"`{'` `'.join(prop.evaluate.__code__.co_varnames)}`"
if isinstance(prop, xplt.properties.DerivedProperty)
else ""
),
]
# https://github.com/jupyter-book/jupyter-book/issues/1501#issuecomment-2301641068
display(Markdown(df.to_markdown()))
display_property_info(xplt.properties._default_properties)
Property |
Unit |
Symbol |
Description |
Derived from |
---|---|---|---|---|
|
\( \) |
\(n\) |
Turn |
|
|
\( \) |
\(q/q_\mathrm{ref}\) |
Charge ratio |
|
|
\( \) |
\((q/q_\mathrm{ref})/(m/m_\mathrm{ref})\) |
Charge-over-rest-mass ratio |
|
|
\( \) |
\(N\) |
Count |
|
|
\( \) |
\(\delta\) |
||
|
\( \mathrm{eV} \) |
\(E\) |
Total energy |
|
|
\( \frac{\mathrm{eV}}{\mathrm{c}^{2}} \) |
\(m\) |
Rest mass |
|
|
\( \frac{\mathrm{eV}}{\mathrm{c}^{2}} \) |
\(m_\mathrm{ref}\) |
Reference rest mass |
|
|
\( \) |
\(p_\tau\) |
||
|
\( \) |
\(x'\) |
||
|
\( \) |
\(y'\) |
||
|
\( \) |
\(p_\zeta\) |
||
|
\( \mathrm{e} \) |
\(q\) |
Charge |
|
|
\( \mathrm{e} \) |
\(q_\mathrm{ref}\) |
Reference charge |
|
|
\( \mathrm{m} \) |
\(s\) |
||
|
\( \mathrm{m} \) |
\(\tau\) |
||
|
\( \mathrm{m} \) |
\(x\) |
||
|
\( \mathrm{m} \) |
\(\langle x \rangle\) |
||
|
\( \mathrm{m} \) |
\(\sigma_x\) |
||
|
\( \mathrm{m} \) |
\(y\) |
||
|
\( \mathrm{m} \) |
\(\langle y \rangle\) |
||
|
\( \mathrm{m} \) |
\(\sigma_y\) |
||
|
\( \mathrm{m} \) |
\(\zeta\) |
Particle plots#
These plots support normalized coordinates and action-angle-variables.
See Phasespace for usage examples
Show code cell source
display_class_info(xplt.particles.ParticlePlotMixin)
display_property_info(
xplt.particles.ParticlePlotMixin()._init_particle_mixin()["_properties"]
)
Additional default properties applicable only to: ParticleHistogramPlot
ParticlesPlot
PhaseSpacePlot
SpillQualityPlot
SpillQualityTimescalePlot
TimeBinPlot
TimeFFTPlot
TimeIntervalPlot
TimePlot
Property |
Unit |
Symbol |
Description |
Derived from |
---|---|---|---|---|
|
\( \mathrm{m} \) |
\(J_x\) |
|
|
|
\( \mathrm{m} \) |
\(J_y\) |
|
|
|
\( \mathrm{m}^{0.5} \) |
\(X'\) |
|
|
|
\( \mathrm{m}^{0.5} \) |
\(Y'\) |
|
|
|
\( \mathrm{m}^{0.5} \) |
\(X\) |
|
|
|
\( \mathrm{m}^{0.5} \) |
\(Y\) |
|
|
|
\( \mathrm{s} \) |
\(t\) |
|
|
|
\( \mathrm{m} \) |
\(\zeta\) |
|
|
|
\( \mathrm{rad} \) |
\(Θ_x\) |
|
|
|
\( \mathrm{rad} \) |
\(Θ_y\) |
|
Histogram plots#
Show code cell source
display_class_info(xplt.particles.ParticleHistogramPlotMixin)
display_property_info(xplt.particles.ParticleHistogramPlotMixin()._init_particle_histogram_mixin()["_properties"]) # fmt: skip
Additional default properties applicable only to: ParticleHistogramPlot
TimeBinPlot
TimeFFTPlot
TimeIntervalPlot
Property |
Unit |
Symbol |
Description |
Derived from |
---|---|---|---|---|
|
\( \mathrm{e} \) |
\(Q\) |
Charge per bin |
|
|
\( \) |
\(N\) |
Particles per bin |
|
|
\( \) |
\(N\) |
Particles (cumulative) |
|
|
\( \frac{\mathrm{e}}{\mathrm{s}} \) |
\(I\) |
Current |
|
|
\( \frac{1}{\mathrm{s}} \) |
\(\dot{N}\) |
Particle rate |
Spill quality plots#
Show code cell source
display_class_info(xplt.timestructure.MetricesMixin)
display_property_info(xplt.timestructure.MetricesMixin._metric_properties)
Additional default properties applicable only to: SpillQualityPlot
SpillQualityTimescalePlot
Property |
Unit |
Symbol |
Description |
Derived from |
---|---|---|---|---|
|
\( \) |
\(c_\mathrm{v}=\sigma/\mu\) |
Coefficient of variation |
|
|
\( \) |
\(F=\langle N \rangle^2/\langle N^2 \rangle\) |
Spill duty factor |
|
|
\( \) |
\(M=\hat{N}/\langle N \rangle\) |
Max-to-mean ratio |
Floor plot#
See Beamline for usage examples
Show code cell source
display_class_info(xplt.line.FloorPlot)
display_property_info(xplt.line.FloorPlot()._default_properties)
xplt.mpl.pyplot.close()
Additional default properties applicable only to: FloorPlot
Property |
Unit |
Symbol |
Description |
Derived from |
---|---|---|---|---|
|
\( \mathrm{m} \) |
\(X\) |
||
|
\( \mathrm{m} \) |
\(Y\) |
||
|
\( \mathrm{m} \) |
\(Z\) |
||
|
\( \mathrm{rad} \) |
\(\Phi\) |
||
|
\( \mathrm{rad} \) |
\(\Psi\) |
||
|
\( \mathrm{rad} \) |
\(\Theta\) |
Twiss plot#
See Twiss for usage examples
Show code cell source
display_class_info(xplt.twiss.TwissPlot)
display_property_info(xplt.twiss.TwissPlot()._default_properties)
xplt.mpl.pyplot.close()
Additional default properties applicable only to: TwissPlot
Property |
Unit |
Symbol |
Description |
Derived from |
---|---|---|---|---|
|
\( \) |
\(\alpha_x\) |
||
|
\( \) |
\(\alpha_y\) |
||
|
\( \mathrm{m} \) |
\(\beta_x\) |
||
|
\( \mathrm{m} \) |
\(\beta_y\) |
||
|
\( \) |
\(D_{x'}\) |
||
|
\( \) |
\(D_{y'}\) |
||
|
\( \mathrm{m} \) |
\(D_x\) |
||
|
\( \mathrm{m} \) |
\(D_y\) |
||
|
\( \mathrm{m} \) |
\(x\pm3\sigma_x\) |
|
|
|
\( \mathrm{m} \) |
\(y\pm3\sigma_y\) |
|
|
|
\( \mathrm{m} \) |
\(x\pm\sigma_x\) |
|
|
|
\( \mathrm{m} \) |
\(y\pm\sigma_y\) |
|
|
|
\( \frac{1}{\mathrm{m}} \) |
\(\gamma_x\) |
||
|
\( \frac{1}{\mathrm{m}} \) |
\(\gamma_y\) |
||
|
\( \mathrm{m} \) |
\(x_\mathrm{max}\) |
||
|
\( \mathrm{m} \) |
\(y_\mathrm{max}\) |
||
|
\( \mathrm{m} \) |
\(x_\mathrm{min}\) |
||
|
\( \mathrm{m} \) |
\(y_\mathrm{min}\) |
||
|
\( \) |
\(\mu_x\) |
||
|
\( \) |
\(\mu_y\) |
||
|
\( \) |
\(\sigma_{x'}\) |
||
|
\( \) |
\(\sigma_{y'}\) |
||
|
\( \) |
\(\sigma_{p_\zeta}\) |
||
|
\( \mathrm{m} \) |
\(\sigma_x\) |
||
|
\( \mathrm{m} \) |
\(\sigma_y\) |
||
|
\( \mathrm{m} \) |
\(\sigma_\zeta\) |