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 - Interactive histogramming (1D & 2D)
- Gaussian fitting with Python’s lmfit
- UI-based histogram and cut definition
- Custom histogram scripting
- 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. 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.
If there are issues reading ROOT files or you have additional requests, please open an issue or contact me — I can add support for more ROOT structures.
In the future, I plan to add the ability to read ROOT trees directly and perform histogramming within Spectrix.
For now, ROOT trees can easily be converted to .parquet format using HEP-Convert.
Use the Get Files 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 a .root file is selected, Spectrix attempts to load all 1D and 2D histograms found in that file.
Histogram paths such as /name1/name2/histogram_name are preserved and used to organize views into nested container hierarchies.
Parquet is the preferred format for analysis, since Spectrix can build histograms directly from raw columns using the Histogram Script system.
If you are unsure of available columns, open Selected File Settings and click Get Column Names.
Spectrix will list columns from the selected parquet files.
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 and writes output using filename_{suffix}.parquet naming.
⚠️ Warning:
Combining files loads all selected data into memory. Very large datasets may exhaust RAM and crash the session.Recommended approach: apply cuts first to reduce data volume, then combine reduced files.
The Histogram Script panel can be opened or closed using the “Histograms” button under the “Get Files” button.
This tool allows you to:
- 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 inspect available column names.
- Create any derived columns you need (for example timing differences or calibrated values).
- Define cuts (1D expressions 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, or calibrated variants of existing columns.
Derived columns can then be used exactly like native columns in cuts and histogram definitions.
⚠️ Tip:
Define column aliases (names) without spaces.
This is required for correct parsing in string-based 1D cut expressions.
You can define:
- 1D cuts by providing a cut name and a logical expression.
- 2D cuts as graphical polygons in the 2D histogram view (these appear as active 2D histogram cuts and can be toggled on/off).
For 2D cuts, you can:
- Load a cut JSON individually.
- Add a cut folder to load multiple cut files.
- Use active 2D histogram cuts created interactively in the plot, even before saving them to disk.
For expression-based 1D cuts, use valid column names and logical operators such as & to combine conditions.
Common operators in 1D cut expressions include:
&for AND|for OR==,!=,>,>=,<,<=for comparisons
Example:
(Column1Energy > 400) & (Column1Energy < 1200) & (Column2Time != -1e6)
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 must exactly match a column name from the .parquet file or a previously created alias.
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.
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.
- Rebin and restyle plots from the context menu.
- Store fit results and review them in a dedicated side panel.
- 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.
- 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 on the plot neary = 0. - 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).
- 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. |
| 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. |
| S | Store fit | Saves current fit result for later comparison/export. |
| Tab | Toggle Fit Panel | Opens/closes side panel for stored fits. |
| I | Toggle statistics | Shows/hides stats such as mean, counts, and sigma. |
| L | Toggle log Y-axis | Switches between linear and logarithmic Y scaling. |
- The default background model is Linear.
- 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.
- 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.
- Fit reports, curves, and parameter values are available from the plot context menu.
Additional controls such as rebinning, marker styling, and display options are available by right-clicking on the 1D plot.
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.
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 2D Histogram Cut and be toggled on/off for histogram generation.
- Saved cuts can be reloaded, recolored, and reopened for vertex editing.
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



