Time evolution
TimeEvolution(time, values) holds one quantity sampled at absolute times. time is stored as DateTime; unitful unix timestamps (as found in the hit and evt tiers) are converted on construction. values may carry units and Measurement uncertainties. Timestamps must be sorted.
Three functions derive new series from existing data, and each result is again a TimeEvolution, so they compose:
using LegendEventAnalysis, Unitful
ts = TimeEvolution(timestamp, e_pulser) # raw pulser energies, one per event
s = smooth(ts, 1u"hr") # mean ± std per hour, one point per window
g = relative(s, 6u"hr") # deviation in percent from the first 6 hours
r = rate(timestamp, 10u"minute") # events per second, √N uncertaintiessmooth(ts, Δt)averages over consecutive windows of widthΔtand reports the spread of each window as the uncertainty.relative(ts, reference)normalizes to the mean of the firstreferencesamples (anInteger) or of the samples within a time span after the first timestamp. Units cancel; uncertainties propagate.rate(timestamps, Δt)counts events per window and reports the rate in Hz. Only windows fully covered by the data span are included.
Window widths and reference spans accept Dates.Periods (Hour(1)) as well as unitful times (1u"hr").
smooth takes any statistic as a third argument; mean (the default) adds the window spread as uncertainty and extrema yields ClosedIntervals, which plot as an envelope:
smooth(ts, 1u"hr", median) # median per window
smooth(ts, 1u"hr", std) # spread per window, e.g. to monitor the resolution
smooth(ts, 1u"hr", maximum) # or minimum, or v -> quantile(v, 0.99)
smooth(ts, 1u"hr", extrema) # min .. max per windowWhole-series statistics and selection:
mean(ts), std(ts), median(ts), extrema(ts), minimum(ts), maximum(ts)
findmax(ts), findmin(ts) # (value, time) of the extreme sample
ts[t1 .. t2] # samples within a ClosedInterval of DateTime or unix times
filter(>(1005u"keV"), ts) # samples whose values satisfy a predicateTime-evolution plots
Loading LegendMakie and a Makie backend enables lplot and lplot! for TimeEvolution. The examples below use
using LegendMakie, CairoMakie, Dates, Unitful
ts = TimeEvolution(timestamp, e_pulser) # one pulser energy per event
g = relative(smooth(ts, 1u"hr"), 6u"hr") # deviation in percent from the first 6 hours
r = rate(timestamp, 30u"minute") # event rate in HzBasic plot
By default the values are drawn with lines! and their uncertainties as bands at sigmas = (3, 1):
lplot(g)
lplot(g; ylabel = "ΔE (%)", title = "Gain stability", figsize = (1000, 400))Uncertainty styles
lplot(g; sigmas = (1,)) # a single ±1σ band
lplot(g; sigmas = ()) # no bands
lplot(g; uncertainty_style = :bars, plot = scatter!) # ±1σ error bars
lplot(g; uncertainty_style = :bars, whiskerwidth = 0) # error bars without caps
lplot(g; uncertainty_style = :none) # values onlyValues without uncertainties (for example, a TimeEvolution built from plain numbers) draw the line or markers only.
Plot primitive and Makie keywords
plot selects the Makie function used for the values; keywords that are not consumed by lplot are forwarded to it:
lplot(g; plot = scatter!, markersize = 6)
lplot(g; plot = scatterlines!, linestyle = :dash, marker = :diamond)
lplot(g; color = :red, linewidth = 3, label = "Pulser")Boundaries, axis options, watermark
lplot(g; boundaries = run_start_times) # dashed vertical lines
lplot(g; ylims = (-0.3, 0.3))
lplot(g; axis = (; xticklabelrotation = π/6)) # any other Axis attribute
lplot(g; watermark = true, watermark_options = (; position = "outer top", final = false))Overlaying series
lplot!(ax, ts) adds a series to an existing axis:
fig = lplot(g; label = "Pulser", ylabel = "ΔE (%)")
ax = content(fig[1, 1])
lplot!(ax, relative(smooth(cusp, 1u"hr"), 6u"hr"); color = :red, label = "E_cusp")
axislegend(ax)
figEnvelopes
Interval-valued series from smooth(ts, Δt, extrema) draw both edges and the filled band between them:
fig = lplot(smooth(ts, 1u"hr", extrema); label = "min–max", ylabel = "Pulser energy")
lplot!(content(fig[1, 1]), smooth(ts, 1u"hr", median); color = :red, label = "median")
axislegend(content(fig[1, 1]))Several panels
lplot!(ts; row, col) adds a new axis to the current figure. Unitful values label the axis with their unit:
fig = lplot(g; ylabel = "ΔE (%)")
lplot!(r; row = 2, plot = scatter!, uncertainty_style = :bars, ylabel = "Rate")
lplot!(smooth(ts, 1u"hr"); row = 1, col = 2, ylabel = "Pulser energy")
fig