Spectrix is a comprehensive software package for nuclear spectrum analysis. It provides tools for histogramming, Gaussian fitting, and interactive visualization of 1D and 2D histograms using the crates:
egui, egui-tiles, egui_plot, and polars.
Additionally, using uproot, you can view 1D and 2D ROOT histograms. Fitting is performed using Python’s lmfit library.
- Read and analyze
.parquetand.rootfiles - Background ROOT histogram retrieval/export so long uproot operations do not block the UI
- Combine matching ROOT histograms across multiple files, or load them separately with per-file prefixes
- Interactive histogramming (1D & 2D)
- Interactive histogram-created cuts for 1D and 2D views
- Gaussian fitting with Python’s lmfit, including total-fit uncertainty bands
- Visible-range auto-Y scaling for 1D histograms, with log-Y support
- UUID peak labels with configurable size/lift and optional guide lines
- UI-based histogram and cut definition
- Custom histogram scripting
- Built-in screenshot capture from the top bar
- Integration with Polars for high-performance data processing
If you want the simplest launch path, use:
./spectrix.shThis script creates/activates .venv, installs Python dependencies, sets the required PyO3 environment variables, and runs cargo run --release.
- macOS Sonoma 14.6.1 on Apple M3 MacBook Pro (18 GB RAM)
- Ubuntu 22.04.5 LTS
- Windows 10
⚠️ Tested with Python 3.13.
On Windows, ensure that Python is downloaded from python.org.
Ensure you’re using the latest stable version of Rust:
rustup updateIf you don’t have Rust installed, visit the Rust website and follow the instructions.
Linux (Ubuntu/Debian):
sudo apt-get install libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev libxkbcommon-dev libssl-dev libgtk-3-devmacOS:
Install equivalent libraries using Homebrew as needed for your local toolchain. If build/linking issues appear, run through ./spectrix.sh first to ensure the Python/PyO3 environment is configured correctly.
Clone the repository
git clone https://github.com/alconley/spectrix.git
cd spectrixCreate a Python virtual environment and activate it
python3 -m venv .venv
source .venv/bin/activateInstall the required python packages
pip install -r requirements.txt(Optional, but often required on macOS; see ./spectrix.sh) Set the Python environment for Rust (PyO3)
export PYO3_PYTHON=$(pwd)/.venv/bin/python
export PYTHONPATH=$(pwd)/.venv/lib/python3.*/site-packagesRun the Rust project in release mode
cargo run --releaseTips if the program doesn't run
rustup update
cargo clean
cargo updateThe Spectrix program reads .parquet files using the Polars crate.
Typically, .parquet files are generated by Eventbuilder for me. These files store raw data as f64 in a dataframe format (similar to a ROOT tree).
Histograms can be configured in the left panel of the UI. New column creation and cuts can also be performed directly in the UI.
Additionally, users can read 1D and 2D histograms from ROOT files using the Python package uproot. ROOT trees can easily be converted to .parquet format using HEP-Convert.
Use the Get Files/Directory button to select either a single file or a directory.
- If you select a directory, Spectrix scans it and loads supported files (
.parquet,.root). - If you select a single file, only that file is loaded.
If one or more .root files are selected, Spectrix attempts to load all 1D and 2D histograms found in those files.
Histogram paths such as /name1/name2/histogram_name are preserved and used to organize views into nested container hierarchies.
ROOT retrieval runs in the background, so the UI remains responsive while Spectrix reads histograms through uproot. A spinner is shown while retrieval is active, and the operation can be canceled between files.
ROOT loading behavior depends on the Calculate/Get histograms separately toggle:
- Off: histograms with the same full ROOT path/name are merged together across the selected files.
- On: each file gets its own prefix using the file stem, so matching histograms are loaded as separate entries such as
run_001/hEnergyandrun_002/hEnergy.
When you start a new ROOT retrieval, Spectrix clears the current histogram contents first so repeated clicks on Get Histograms do not double the loaded counts.
After 1D ROOT histograms are loaded, their axes are reset automatically so the plot opens around the imported data instead of staying zoomed near zero.
Parquet is the preferred format for analysis, since Spectrix can build histograms directly from raw columns using the Histogram Script system.
When one or more .parquet files are selected, Spectrix loads the column names automatically when needed so the searchable pickers in the Histogram Script stay populated.
You can also refresh them manually with Get Column Names in the Processor menu.
In the same section, you can:
- Save filtered versions of your
.parquetfiles. - Combine multiple files into one.
You can also load 2D cuts in this area; those cuts are then available as active cuts and are used when filtering saved .parquet outputs.
When saving filtered files, Spectrix applies all enabled active 1D/2D cuts from the Histogram Script cut sections and writes output using filename_{suffix}.parquet naming.
Interactive cuts created directly on 1D and 2D histograms also appear in the same active-cuts area, so they can be enabled/disabled for histogram generation and parquet filtering before being added manually to the script.
When combining parquet files, Spectrix scans the selected inputs lazily and streams the merged result directly to the output parquet sink. It does not collect the full combined dataset into memory first.
Large combines can still take time and produce large output files, so reducing files with cuts first can still be a useful workflow when you only need a subset of the data.
The Histogram Script panel can be opened or closed using the “Histograms” button under the “Get Files” button.
This tool allows you to:
- Define reusable numeric variables.
- Define new analysis columns from existing parquet columns.
- Define and manage 1D and 2D cuts.
- Define 1D and 2D histograms (name, columns, bins, range, and applied cuts).
- Save/load complete histogram-script setups as
.jsonconfiguration files.
- Load one or more parquet files and make sure the column names are available.
- Add reusable variables if you want named constants such as calibration coefficients.
- Create any derived columns you need with the computed-column builder.
- Define cuts with the 1D cut builder and/or 2D graphical cuts.
- Create histogram definitions and attach active cuts.
- Save the configuration to JSON so the same analysis can be reused.
Below are example images of Spectrix using the sample file located at
./example/run_83_reduced.parquet.
This dataset comes from a one-hour measurement of the 52Cr(d,pγ)53Cr reaction.
The file is pre-filtered to include only proton data (the full dataset was too large for GitHub).
Invalid detector values are stored as -1e6, which marks cases where a detector did not register a hit within an event window.
This ensures that all columns have the same length.
The file was generated using Eventbuilder.
The following subsections assume you are in the “General” section of the Histogram Script panel.
You can create derived columns such as time differences, sums, averages, calibrated values, or polynomial-style transforms.
Derived columns can then be used exactly like native columns in cuts and histogram definitions.
The computed-column UI now uses a dedicated Builder panel:
- The table row shows the column alias, a Builder button, the term count, and a one-line expression summary.
- The builder opens below the table and edits one computed column at a time.
- Aliases are sanitized automatically so they only contain letters, numbers, and underscores.
- Column and variable selection uses searchable combo boxes.
- Each term can be:
ColumnorConstant- added or subtracted from the expression
- multiplied by a coefficient that is a
Value,Variable, or anotherColumn - raised to a power, including fractional powers such as
0.5
The Variables section lets you define reusable named constants such as a, m, and c.
- Variable names follow the same identifier rules as column aliases: letters, numbers, and underscores only.
- Variable names cannot safely overlap with real or computed column names.
- Variables can be reused in any computed-column term where the coefficient type is set to Variable.
Example:
a = 2.5m = -1.2c = 15.0
You can then reuse those values in multiple computed columns without retyping them each time.
Average of two focal-plane channels
- Add a new column and set the alias to
Xavg_manual. - Open Builder.
- Add two terms:
- first term:
Column, coefficientValue = 0.5, source columnX1, power1 - second term:
+ Column, coefficientValue = 0.5, source columnX2, power1
- first term:
This produces:
(0.5 * X1) + (0.5 * X2)
Square-root calibration using variables
- Define variables
a = 3.0andc = -12.0. - Add a new column and set the alias to
Xsqrt_cal. - Open Builder.
- Add two terms:
- first term:
Column, coefficientVariable = a, source columnXavg, power0.5 - second term:
+ Constant, coefficientVariable = c
- first term:
This produces:
(a * Xavg ** 0.5) + (c)
You can define:
- 1D cuts with the builder UI, or by loading saved 1D cut JSON files with
+1D Load. - 2D cuts as graphical polygons in the 2D histogram view.
For cut management in the Histogram Script UI, you can:
- Add a blank 1D cut with
+1D Manual. - Load a saved 1D cut with
+1D Load. - Load a cut JSON individually for 2D cuts with
+2D. - Add a cut folder to load multiple cut files.
- Use Active Histogram Cuts created interactively in 1D or 2D plots, even before saving them to disk.
The 1D cut UI is builder-first:
- Click Builder in the cut row to open the dedicated editor below the table.
- Each Expression is one parenthesized group.
- Conditions inside the same expression are combined with AND.
- Separate expressions are combined with OR.
- Each condition uses:
- a searchable column picker
- an operator picker
- a numeric value field
- Use Add Condition to add another AND clause to the current expression.
- Use Add OR Expression to start a new OR group.
Supported comparison operators in the builder are:
>>=<<===!=
Spectrix automatically generates the underlying logical expression string from the builder, so the user does not need to type it manually.
Single range gate
- Add a 1D cut with
+1D Manual. - Name it
Column1Window. - Open Builder.
- In
Expression 1, add:- condition 1: column
Column1, operator>=, value-100 - condition 2: column
Column1, operator<=, value100
- condition 1: column
This produces:
((Column1 >= -100) & (Column1 <= 100))
Two alternative gates joined with OR
- Add a 1D cut and name it
GoodColumns. - Open Builder.
- In
Expression 1, add:- condition 1: column
Column1, operator>=, value0 - condition 2: column
Column1, operator<=, value4096
- condition 1: column
- Click Add OR Expression.
- In
Expression 2, add:- condition 1: column
Column2, operator>=, value0 - condition 2: column
Column2, operator<=, value4096
- condition 1: column
This produces:
((Column1 >= 0) & (Column1 <= 4096)) | ((Column2 >= 0) & (Column2 <= 4096))
Cuts that were loaded from disk or explicitly saved to disk remember their save path. If you later edit the cut name or cut values inside Spectrix, the cut is automatically re-saved back to that same file.
Only cuts enabled in the corresponding UI checkboxes are applied during histogram generation and parquet filtering.
Enter the histogram name and select the input column(s), bin count, and axis range.
Using slashes (/) in histogram names automatically groups plots into nested containers.
The “Column(s)” field now uses searchable pickers, so histogram source columns can be chosen directly from the loaded parquet columns or previously created aliases. Then specify range, binning, and which active cuts should be applied.
If a cut is defined but not enabled, it will not affect that histogram.
Histogram Script definitions can be saved to JSON and loaded later.
This is useful for:
- Reproducing the same analysis between runs.
- Sharing analysis setups with collaborators.
- Building experiment-specific templates that can also be used by Custom Scripts.
- A screenshot button lives in the top bar next to the light/dark theme toggle. Clicking it prompts for a save location and writes the current Spectrix window as a
.png. - In the session context menu, Reset Histogrammer is placed directly beside the Histogrammer menu button for quicker access during iterative analysis.
The Custom Scripts section provides a UI-based way to define and load pre-configured histogram setups.
These scripts act as a front-end to the Histogram Script, allowing users to quickly initialize commonly used columns, cuts, and histograms without manually creating them each time.
In other words, the Custom Scripts system automatically generates a full histogram configuration through the interface — simplifying setup for frequent or experiment-specific analyses.
Currently, the included custom scripts are tailored for work relevant to Florida State University (FSU) experiments and setups.
These include example configurations for detector systems such as SE-SPS, ICESPICE, and CeBrA.
Each custom script automatically populates the Histogram Script panel with:
- Commonly used columns (e.g., timing differences)
- Predefined cuts for data selection
- Standard 1D and 2D histograms for quick visualization and analysis
The Custom Scripts system was designed to be easily adaptable for adding new configurations. If you want help creating one, open an issue and include your experiment-specific requirements.
For those at FSU, the SE-SPS custom configuration is currently the most complete and ready for use.
The other scripts are still under development as part of the ongoing experimental setup.
The 1D histogram interface in Spectrix is designed for fast, interactive peak fitting and inspection, with a workflow centered on markers, region selection, and stored fit results.
- Interactively place and move peak, background, and region markers.
- Fit one or many Gaussian peaks in a selected region.
- Choose and tune background models: linear, quadratic, power law, exponential.
- Detect peaks with
find_peaks, with optional region-limited searching and background subtraction. - Optionally draw an uncertainty band around the total Gaussian fit from the Fit Panel.
- Auto-fit the Y axis to the tallest bin in the current visible X range.
- Rebin and restyle plots from the context menu.
- Create interactive 1D cut regions directly on the histogram and reuse them as active cuts.
- Store fit results and review them in a dedicated popup window or from the right-click Fits menu.
- Open the Fit Panel either inside Spectrix or as a separate native window with Pop Out when the backend supports extra viewports.
- Click Modify on a stored fit to move it back into the temp fit editor with its saved markers/settings.
- Click Refit in the Fit Panel header to re-run all stored fits on the latest incoming data.
- View histogram statistics in both raw-channel and calibrated display modes.
- Adjust UUID label size/lift and optionally draw a guide back to the composition curve.
- Use keyboard-driven controls for quick analysis loops.
Spectrix uses Python lmfit for nonlinear fitting, called from Rust via PyO3.
Fitting was originally implemented with varpro, but lmfit now powers the current pipeline because it provides flexible model composition, robust parameter constraints, and detailed fit reporting with less custom maintenance.
Each fitted Gaussian peak carries two pieces of analysis metadata:
- UUID: an integer identifier used to track the same physical state across fits and downstream analysis steps. If the UUID is not
0, its number is drawn above the fitted composition peak. UUID text follows the light/dark theme, stays out of the legend, and can be resized/lifted with an optional dashed guide line from the Fit Panel. - Assigned energy: reference energy (and uncertainty) used to build a channel-to-energy calibration.
If a peak has no assigned energy, Spectrix stores -1 as the invalid sentinel value (with zero uncertainty). Peaks with energy -1 are ignored when calibration points are collected.
Calibration is built from stored fits using peak centroids (mean) versus assigned energies:
- Linear calibration requires at least 2 valid points.
- Quadratic calibration requires at least 3 valid points.
After solving for calibration coefficients, Spectrix propagates uncertainties and attaches calibrated quantities to fit parameters.
This metadata is also written into the underlying lmfit ModelResult payload:
- peak UUID (
g{i}_uuid) - assigned energy and uncertainty (
g{i}_energy,g{i}_energy_uncertainty) - calibrated Gaussian parameters, including
g{i}_center_calibrated,g{i}_sigma_calibrated,g{i}_fwhm_calibrated, plus calibrated copies for area/amplitude/height - calibration constants and uncertainties, including
calibration_a,calibration_b,calibration_c, andcalibration_a_uncertainty,calibration_b_uncertainty,calibration_c_uncertainty - fit marker metadata for Python interoperability:
region_marker_count,region_marker_0,region_marker_1, ...peak_marker_count,peak_marker_0,peak_marker_1, ...bg_marker_count,bg_marker_start_0,bg_marker_end_0, ...- fit/background flags:
bg_model_type,fit_equal_sigma,fit_free_position
Stored-fit modify/refit behavior:
- Modify removes the selected fit from the stored list, restores its marker/background settings, and moves it into the temp-fit slot for editing.
- On refit, Spectrix preserves existing UUID and assigned-energy values by remapping prior assignments onto the new fitted peak means.
- If background model is
None, no background markers are restored/generated.
Because of that, exported lmfit .sav files include both fit parameters and calibration/UUID context, so they can be loaded and further analyzed directly in Python (for example with lmfit.model.load_modelresult).
When an exported lmfit .sav file is loaded back into Spectrix, the total-fit 1σ uncertainty band is rebuilt immediately. Spectrix first tries lmfit eval_uncertainty; if the saved result cannot provide that directly, Spectrix falls back to an approximate band reconstructed from the stored parameter errors.
- Save Fits / Load Fits (
.json): best for restoring and continuing your work inside Spectrix. - Export All lmfit Results / Load lmfit
.sav: best when you want to continue analysis in Python withlmfit. - If you are not planning to continue in Python/lmfit, prefer Save Fits / Load Fits.
Cursor must be inside the plot for keybinds to be active.
| Key | Action | Notes |
|---|---|---|
| P | Add peak marker | Places a Gaussian peak marker at cursor position. |
| B | Add background marker | Used for background-only sampling points. |
| C | Create 1D cut | Creates a draggable 1D cut region using the histogram’s current source column. |
| R | Add region markers | Define fit interval; drag marker center with middle mouse button. |
| - | Remove nearest marker | Deletes marker closest to cursor. |
| Delete | Clear temporary markers/fits | Removes active markers and temporary fit curves. |
| G | Fit background | Uses selected background model and current background markers. |
| F | Fit Gaussians | Fits peaks in region; auto-fits background first if needed. |
| O | Detect peaks | Runs the peak finder and places peak markers at the detected locations. |
| S | Store fit | Saves current fit result for later comparison/export. |
| I | Toggle statistics | Shows/hides stats such as mean, counts, and sigma for the current visible range. |
| L | Toggle log Y-axis | Switches between linear and logarithmic Y scaling while keeping the current X range. |
| Y | Toggle auto-fit Y | Fits Y to the tallest visible bin with about 15% headroom. |
- The default background model is Linear.
- 1D auto-fit Y is enabled by default and uses the maximum bin height in the current visible X range with
1.15xheadroom in both linear and log modes. - If no background markers are present, Spectrix will still fit Gaussians on top of a fitted background model.
- Background markers and an explicit background fit help the solver converge faster and let you control which region is used to determine the background.
- Multiple Gaussian peaks can be fit simultaneously when multiple peak markers exist in the active region.
- Peak finding settings are available from the right-click Peak Finder submenu, including min/max height, prominence, difference, plateau size, and distance controls with hover help.
- If exactly two region markers are active, peak finding only searches the data between them.
- If a background fit is active, Spectrix subtracts that background before peak finding.
- Detected peaks are written back into the plot as peak markers so they can be fitted immediately.
- The 1σ Uncertainty checkbox under Show Fit Lines toggles the total Gaussian uncertainty band.
- That total-fit uncertainty band uses lmfit
eval_uncertaintyat1σ. - By default, peaks share a common standard deviation; this can be changed in fit settings.
- Peak positions and widths can be constrained or locked from the Fits menu.
- UUID labels are drawn above the composition curve using the larger of the composition height or the tallest nearby bin, so they stay readable on real peaks.
- The UUID Labels controls in the Fit Panel let you change label Size, Lift, and an optional dashed Guide line back to the composition curve.
- The Fit Panel can be popped out into its own window with the Pop Out toggle next to Show Fit Panel; if native child windows are unavailable, egui falls back to an embedded window.
- Pop-out Fit Panel contents follow the active light/dark theme, including the UUID label colors drawn on fit plots.
- Fit reports, curves, and parameter values are available from the plot context menu.
Additional controls such as peak finding, rebinning, marker styling, and display options are available by right-clicking on the 1D plot.
- Press C (or use the right-click Cuts menu) to create a new interactive 1D cut.
- The cut starts as two vertical lines spanning slightly inside the current visible X range.
- You can drag either boundary line directly.
- You can also click and drag between the two lines to move the entire cut window while keeping the same width.
- A default cut name is generated automatically in the form
Histogram Name 1D Cut N. - The cut expression is generated as
(ColumnName >= (x1)) & (ColumnName <= x2). - 1D cuts created interactively in the plot appear in the Active Histogram Cuts area of the Histogram Script.
- The cut Info menu shows the parsed column name, lower bound, upper bound, full expression, and saved path.
- If a 1D cut was loaded from disk or previously saved to disk, changing the cut name or moving the cut region will automatically re-save it to the same path.
- 1D cuts created on 2D projection windows inherit the projection axis column name automatically.
The 2D histogram interface in Spectrix is optimized for fast visual exploration, gated selection, and axis projection workflows.
- Navigate and inspect dense 2D distributions interactively.
- Create X and Y projections directly from selected regions.
- Draw and edit polygon gates for event selection.
- Switch colormaps, reverse palettes, and toggle log/linear normalization.
- Rebin data and tune Z-scale display ranges.
- Save and reuse graphical cuts from the plot context menu.
- Reuse histogram-created cuts through the shared active-cuts area in the Histogram Script.
Cursor must be inside the plot for keybinds to be active.
| Key | Action | Notes |
|---|---|---|
| X | Create X projection | Creates an X projection region initialized slightly smaller than the current axis span. |
| Y | Create Y projection | Creates a Y projection region initialized slightly smaller than the current axis span. |
| I | Toggle statistics | Shows/hides summary stats such as mean, counts, and sigma. |
| M | Change colormap | Cycles through available colormap presets. |
| Z | Toggle normalization | Switches between logarithmic and linear color scaling (default is log). |
| R | Reverse colormap | Flips the active colormap direction. |
| C | Create graphical cut | Click to add vertices, drag to edit, double-click to finish polygon. |
- Pressing X or Y creates a projection region that starts slightly smaller than the visible axis limits.
- Projection boundary lines can be adjusted by clicking and dragging the center dot on a boundary line.
- Clicking and dragging between the two projection lines translates the whole projection window while keeping the same width.
- You can also right-click the 2D plot and open Projections in the context menu to adjust projection values directly.
- Press C (or add a cut from the right-click menu) to start a new interactive polygon cut.
- Click to add each vertex.
- Double-click to finish the polygon.
- After creation, click and drag a vertex to reposition it.
- The cut auto-populates the X/Y column names from the current 2D histogram axes; verify these before saving.
- A default cut name is generated automatically in the form
Y v X Cut N(for exampleE2 v E1 Cut 1), and you can rename it before saving. - Use Save to write the cut to JSON for reuse.
- Even if a cut is not saved to disk yet, it can still appear in the Histogram Script as an Active Histogram Cut and be toggled on/off for histogram generation.
- The cut Info menu shows the X/Y columns and saved path.
- Saved cuts can be reloaded, recolored, and reopened for vertex editing.
- If a 2D cut was loaded from disk or previously saved to disk, changing the cut name or moving vertices will automatically re-save it to the same path.
Right-click on the 2D plot for additional controls, including rebinning, colormap/color-scale tuning, projection options, and cut management.
The Analysis feature in Spectrix is still in a preliminary stage, but it establishes the groundwork for more advanced data interpretation and reaction analysis tools planned for future versions.
At this stage, the focus is on cross-section analysis for SE-SPS experiments.
This analysis module utilizes the fit results generated in the Histogrammer to extract information about the yield of each excited state.
By combining the fitting data with experimental parameters — such as reaction information, beam current integrator data, and other relevant metadata — Spectrix can calculate and plot the cross section for each excited state.
Each state is tracked and referenced using a UUID (Universally Unique Identifier), which ensures that every fitted peak and corresponding physical quantity can be uniquely identified and associated across multiple analysis steps.
This makes it straightforward to compare results between datasets or refine fits without losing the connection to the original event or energy level.
While the SE-SPS analysis is currently the only implemented module, the system is designed to be modular and easily expandable.
⚠️ Note:
The SE-SPS cross-section analysis is still experimental and under active development
