Skip to content

Commit

Permalink
modified: README.md
Browse files Browse the repository at this point in the history
	modified:   src/histoer/histo2d/colormaps.rs
	modified:   src/histoer/histogrammer.rs
	modified:   src/histogram_scripter/histogram_script.rs
  • Loading branch information
alconley committed Nov 14, 2024
1 parent 31128c0 commit dd7e154
Show file tree
Hide file tree
Showing 4 changed files with 448 additions and 71 deletions.
31 changes: 2 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ On Fedora Rawhide you need to run:

## Overview

Spectrix program reads in `.parquet` files using the [Polars](https://docs.rs/polars/latest/polars/) crate. Personally, the .parquet files that I use are from [Eventbuilder](https://github.com/alconley/Eventbuilder). Here the parquet files are a dataframe (similar to a root tree) that stores the raw data as an f64. The histograms are calculated off the file "src/histogram_scripter/manual_histogram_script.rs". This file can be easily modified to calculate different histograms. There is also an option to modify/add/remove histograms from the gui. I want to rework this in the future to make it so everything can be configured from the ui, but for now the file "src/histogram_scripter/configure_lazyframes.rs" would have to be adjusted if you want to use this. To change between the manual and gui script, just check the box in the Histogram Script panel.
Spectrix program reads in `.parquet` files using the [Polars](https://docs.rs/polars/latest/polars/) crate. Personally, the .parquet files that I use are from [Eventbuilder](https://github.com/alconley/Eventbuilder). Here the parquet files are a dataframe (similar to a root tree) that stores the raw data as an f64. The histograms can be configured in the right panel in the ui. New column creation/cuts can also be done in the ui.

Additionally, the user can read in a 1D and 2D histograms from a root file using the python package: uproot. The user has to select "Root Files" in the Workspace for the files to appear in the gui. If there is an issure reading root files/additional requests let me know and I can try to add them. In the future, I would like to have the option to read in a root tree, and perform histogramming. However, for now, a root tree can be easily converted to a the parquet format using [hep-convert](https://hepconvert.readthedocs.io/en/latest/root_to_parquet.html).

Expand Down Expand Up @@ -125,31 +125,4 @@ Keybinds (cursor must be in the plot):
- X and Y Projections
- Different Colormaps with that can be reversed, log norm, and adjustable Z range
- Easy to draw cut/gates
- Rebinning

### Cutting/Gating Data

A powerful feature of this program is the ability to filter data using cuts or gates on a 2D histogram. This is done by drawing a polygon around the region of interest, saving the file, and then loading it into the program through the side panel. When you calculate histograms with cuts, a boolean mask is created to filter the data in the underlying lazy frame based on the columns provided by the user. This option is only availiable with parquet files.

#### Steps to Create a Cut/Gate

1. **Draw a Polygon**: Use the interactive UI to draw a polygon around the region of interest on the 2D histogram. This can be activated by right-clicking on the plot and selecting the "Add Cut" button or pressing "c". To place vertices of the polygon, click around the data of interest. Double-click the final point to complete the polygon. The vertices can be moved using left mouse button.

2. **Save and Load the Cut**: Once the polygon is drawn, either save the cut somewhere on your computer and load it or hit the "Retrieve Active Cuts" button in the info panel.

3. **Filter the Lazy Frame**: A boolean mask will be computed for the specified columns (the user must specify which columns to filter). The entire lazy frame will be filtered using this boolean mask. Multiple cuts can be used; just ensure they are activated (this might be broken right now).

Here is an example of filtering our data using a particle identification 2D histogram. In the example, I select all the data that corresponds to the protons.


### Projecting Data

Another useful feature of the 2D histogram is the ability to project data along the X or Y axis to create 1D histograms. This allows for analysis of data distribution along a particular axis.

#### Steps to Create a Projection

1. **Activate Projection**: To create a projection, right-click on the 2D histogram and select "Add X Projection" (keybind: x) or "Add Y Projection" (keybind: y).

2. **Adjust Projection Lines**: Once the projection is activated, lines will appear on the histogram indicating the range of the projection. These lines can be moved using the left mouse button to select the desired range.

3. **View and Use the Projection**: The projection will generate a 1D histogram based on the selected range. This 1D histogram can be used for further analysis, such as fitting peaks.
- Rebinning
82 changes: 82 additions & 0 deletions src/histoer/histo2d/colormaps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ pub enum ColorMap {
Inferno,
Kindlmann,
ExtendedKindlmann,
Turbo,
Jet,
}

#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize)]
Expand Down Expand Up @@ -128,6 +130,8 @@ impl ColorMap {
ColorMap::ExtendedKindlmann => {
Self::colormap(extended_kindlmann(), count, min_count, max_count, options)
}
ColorMap::Turbo => Self::colormap(turbo(), count, min_count, max_count, options),
ColorMap::Jet => Self::colormap(jet(), count, min_count, max_count, options),
}
}

Expand All @@ -145,6 +149,8 @@ impl ColorMap {
ui.radio_value(self, ColorMap::Inferno, "Inferno");
ui.radio_value(self, ColorMap::Kindlmann, "Kindlmann");
ui.radio_value(self, ColorMap::ExtendedKindlmann, "Extended Kindlmann");
ui.radio_value(self, ColorMap::Turbo, "Turbo");
ui.radio_value(self, ColorMap::Jet, "Jet");
});

if new_colormap != *self {
Expand Down Expand Up @@ -572,3 +578,79 @@ fn extended_kindlmann() -> Vec<(f32, i32, i32, i32)> {
(1.0, 255, 255, 255),
]
}

fn turbo() -> Vec<(f32, i32, i32, i32)> {
vec![
(0.0, 48, 18, 59),
(0.025, 55, 37, 105),
(0.051, 61, 56, 145),
(0.076, 66, 74, 179),
(0.102, 69, 92, 207),
(0.128, 70, 109, 229),
(0.153, 70, 125, 244),
(0.179, 67, 142, 253),
(0.205, 60, 158, 253),
(0.230, 49, 175, 245),
(0.256, 38, 190, 232),
(0.282, 28, 205, 215),
(0.307, 23, 218, 198),
(0.333, 26, 228, 182),
(0.358, 37, 236, 165),
(0.384, 56, 244, 144),
(0.410, 80, 249, 122),
(0.435, 105, 253, 101),
(0.461, 131, 254, 81),
(0.487, 153, 254, 65),
(0.512, 171, 250, 56),
(0.538, 188, 244, 52),
(0.564, 204, 235, 52),
(0.589, 219, 225, 54),
(0.615, 232, 213, 56),
(0.641, 242, 200, 58),
(0.666, 249, 186, 56),
(0.692, 253, 170, 51),
(0.717, 254, 152, 44),
(0.743, 252, 132, 35),
(0.769, 247, 113, 27),
(0.794, 241, 94, 19),
(0.820, 233, 77, 12),
(0.846, 223, 63, 8),
(0.871, 211, 50, 5),
(0.897, 197, 38, 2),
(0.923, 181, 28, 1),
(0.948, 163, 18, 1),
(0.974, 144, 10, 1),
(1.000, 122, 4, 2),
]
}

fn jet() -> Vec<(f32, i32, i32, i32)> {
vec![
(0.0, 0, 0, 127),
(0.04, 0, 0, 159),
(0.08, 0, 0, 191),
(0.12, 0, 0, 223),
(0.16, 0, 0, 255),
(0.2, 0, 63, 255),
(0.24, 0, 95, 255),
(0.28, 0, 127, 255),
(0.32, 0, 159, 255),
(0.36, 0, 191, 255),
(0.4, 0, 223, 255),
(0.44, 0, 255, 255),
(0.48, 63, 255, 223),
(0.52, 95, 255, 191),
(0.56, 127, 255, 159),
(0.6, 159, 255, 127),
(0.64, 191, 255, 95),
(0.68, 223, 255, 63),
(0.72, 255, 255, 31),
(0.76, 255, 223, 0),
(0.8, 255, 191, 0),
(0.84, 255, 159, 0),
(0.88, 255, 127, 0),
(0.92, 255, 95, 0),
(0.96, 255, 63, 0),
(1.0, 255, 0, 0),
]
}
35 changes: 0 additions & 35 deletions src/histoer/histogrammer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -403,41 +403,6 @@ impl Histogrammer {
if let Ok(df) = lf_selected.collect() {
let height = df.height();

// // Parallel filling of histograms
// hist1d_map.par_iter().for_each(|(hist, meta)| {
// if let Ok(col_idx) = df.column(&meta.column_name) {
// if let Ok(col_values) = col_idx.f64() {
// let mut hist = hist.lock().unwrap();
// for value in col_values.into_no_null_iter() {
// if value == -1e6 {
// continue;
// }

// hist.fill(value);
// }
// }
// }
// });

// hist2d_map.par_iter().for_each(|(hist, meta)| {
// if let (Ok(x_values), Ok(y_values)) = (
// df.column(&meta.x_column_name).and_then(|c| c.f64()),
// df.column(&meta.y_column_name).and_then(|c| c.f64()),
// ) {
// let mut hist = hist.lock().unwrap();
// for (x, y) in x_values
// .into_no_null_iter()
// .zip(y_values.into_no_null_iter())
// {
// if x == -1e6 || y == -1e6 {
// continue;
// }

// hist.fill(x, y);
// }
// }
// });

// Parallel filling of 1D histograms
hist1d_map.par_iter().for_each(|(hist, meta)| {
if let Ok(col_idx) = df.column(&meta.column_name) {
Expand Down
Loading

0 comments on commit dd7e154

Please sign in to comment.