Fcs

Struct Fcs 

Source
pub struct Fcs {
    pub header: Header,
    pub metadata: Metadata,
    pub parameters: FxHashMap<ChannelName, Parameter>,
    pub data_frame: Arc<DataFrame>,
    pub file_access: AccessWrapper,
}
Expand description

A struct representing an FCS file

Fields§

§header: Header

The header segment of the fcs file, including the version, and byte offsets to the text, data, and analysis segments

§metadata: Metadata

The metadata segment of the fcs file, including the delimiter, and a hashmap of keyword/value pairs

§parameters: FxHashMap<ChannelName, Parameter>

A hashmap of the parameter names and their associated metadata

§data_frame: Arc<DataFrame>

Event data stored in columnar format via Polars DataFrame (NEW) Each column represents one parameter (e.g., FSC-A, SSC-A, FL1-A) Polars provides:

  • Zero-copy column access
  • Built-in SIMD operations
  • Lazy evaluation for complex queries
  • Apache Arrow interop This is the primary data format going forward
§file_access: AccessWrapper

A wrapper around the file, path, and memory-map

Implementations§

Source§

impl Fcs

Source

pub fn new() -> Result<Self>

Creates a new Fcs file struct

§Errors

Will return Err if:

  • the file cannot be opened,
  • the file extension is not fcs,
  • the TEXT segment cannot be validated,
  • the raw data cannot be read,
  • the parameter names and labels cannot be generated
Source

pub fn open(path: &str) -> Result<Self>

Opens and parses an FCS file from the given path

This is the primary entry point for reading FCS files. It:

  • Validates the file extension (must be .fcs)
  • Memory-maps the file for efficient access
  • Parses the header segment to determine FCS version and segment offsets
  • Parses the text segment to extract metadata and keywords
  • Validates required keywords for the FCS version
  • Generates a GUID if one is not present
  • Loads event data into a Polars DataFrame for efficient columnar access
§Arguments
  • path - Path to the FCS file (must have .fcs extension)
§Errors

Will return Err if:

  • the file cannot be opened or memory-mapped
  • the file extension is not .fcs
  • the FCS version is invalid or unsupported
  • required keywords are missing for the FCS version
  • the data segment cannot be read or parsed
  • parameter metadata cannot be generated
§Example
use flow_fcs::Fcs;

let fcs = Fcs::open("data/sample.fcs")?;
println!("File has {} events", fcs.get_number_of_events()?);
Source

pub fn find_parameter(&self, parameter_name: &str) -> Result<&Parameter>

Looks for the parameter name as a key in the parameters hashmap and returns a reference to it Performs case-insensitive lookup for parameter names

§Errors

Will return Err if the parameter name is not found in the parameters hashmap

Source

pub fn find_mutable_parameter( &mut self, parameter_name: &str, ) -> Result<&mut Parameter>

Looks for the parameter name as a key in the parameters hashmap and returns a mutable reference to it Performs case-insensitive lookup for parameter names

§Errors

Will return Err if the parameter name is not found in the parameters hashmap

Source

pub fn get_parameter_events( &self, channel_name: &str, ) -> Result<&Float32Chunked>

Returns a zero-copy reference to a Polars Float32Chunked view of a column for the parameter

This provides access to the underlying Polars chunked array, which is useful for operations that work directly with Polars types. For most use cases, get_parameter_events_slice() is preferred as it provides a simple &[f32] slice.

§Arguments
  • channel_name - The channel name (e.g., “FSC-A”, “FL1-A”)
§Errors

Will return Err if:

  • the parameter name is not found in the parameters map
  • the column data type is not Float32
Source

pub fn get_parameter_column(&self, channel_name: &str) -> Result<&Column>

Get a reference to the Polars Column for a parameter by channel name

This provides direct access to the underlying Polars column, which can be useful for advanced operations that require the full Polars API.

§Arguments
  • channel_name - The channel name (e.g., “FSC-A”, “FL1-A”)
§Errors

Will return Err if the parameter name is not found in the DataFrame

Source

pub fn get_parameter_events_as_owned_vec( &self, channel_name: &str, ) -> Result<Vec<f32>>

Looks for the parameter name as a key in the ‘parameters’ hashmap and returns a new Vec of the raw event data NOTE: This allocates a full copy of the events - prefer get_parameter_events_slice when possible

§Errors

Will return ‘Err’ if the parameter name is not found in the ’parameters hashmap or if the events are not found

Source

pub fn get_minmax_of_parameter(&self, channel_name: &str) -> Result<(f32, f32)>

Returns the minimum and maximum values of the parameter

§Errors

Will return Err if the parameter name is not found in the ‘parameters’ hashmap or if the events are not found

Source

pub fn generate_parameter_map( metadata: &Metadata, ) -> Result<FxHashMap<ChannelName, Parameter>>

Creates a new HashMap of Parameters using the Fcs file’s metadata to find the channel and label names from the PnN and PnS keywords. Does NOT store events on the parameter.

§Errors

Will return Err if:

  • the number of parameters cannot be found in the metadata,
  • the parameter name cannot be found in the metadata,
  • the parameter cannot be built (using the Builder pattern)
Source

pub fn get_keyword_string_value(&self, keyword: &str) -> Result<Cow<'_, str>>

Looks for a keyword among the metadata and returns its value as a &str

§Errors

Will return Err if the Keyword is not found in the metadata or if the Keyword cannot be converted to a &str

Source

pub fn get_guid(&self) -> Result<Cow<'_, str>>

A convenience function to return the GUID keyword from the metadata as a &str

§Errors

Will return Err if the GUID keyword is not found in the metadata or if the GUID keyword cannot be converted to a &str

Source

pub fn set_guid(&mut self, guid: String)

Set or update the GUID keyword in the file’s metadata

Source

pub fn get_fil_keyword(&self) -> Result<Cow<'_, str>>

A convenience function to return the $FIL keyword from the metadata as a &str

§Errors

Will return Err if the $FIL keyword is not found in the metadata or if the $FIL keyword cannot be converted to a &str

Source

pub fn get_number_of_events(&self) -> Result<&usize>

A convenience function to return the $TOT keyword from the metadata as a usize

§Errors

Will return Err if the $TOT keyword is not found in the metadata or if the $TOT keyword cannot be converted to a usize

Source

pub fn get_number_of_parameters(&self) -> Result<&usize>

A convenience function to return the $PAR keyword from the metadata as a usize

§Errors

Will return Err if the $PAR keyword is not found in the metadata or if the $PAR keyword cannot be converted to a usize

Source

pub fn get_parameter_events_slice(&self, channel_name: &str) -> Result<&[f32]>

Get events for a parameter as a slice of f32 values Polars gives us direct access to the underlying buffer (zero-copy)

§Errors

Will return Err if:

  • the parameter name is not found
  • the Series data type is not Float32
  • the data is chunked (rare for FCS files)
Source

pub fn get_xy_pairs( &self, x_param: &str, y_param: &str, ) -> Result<Vec<(f32, f32)>>

Get two parameters as (x, y) pairs for plotting Optimized for scatter plot use case with zero allocations until the collect

§Errors

Will return Err if either parameter name is not found

Source

pub fn get_event_count_from_dataframe(&self) -> usize

Get DataFrame height (number of events)

Source

pub fn get_parameter_count_from_dataframe(&self) -> usize

Get DataFrame width (number of parameters)

Source

pub fn get_parameter_names_from_dataframe(&self) -> Vec<String>

Get DataFrame column names (parameter names)

Source

pub fn get_parameter_statistics( &self, channel_name: &str, ) -> Result<(f32, f32, f32, f32)>

Aggregate statistics for a parameter using Polars’ streaming API for low memory usage and minimal, chunked passes.

When streaming is enabled, Polars creates a Pipeline:

Source: It pulls a chunk of data from the disk (e.g., 50,000 rows).

Operators: It passes that chunk through your expressions (calculating the running sum, count, min, and max for that specific chunk).

Sink: It aggregates the results from all chunks into a final result.

Because the statistics we are calculating (min, max, mean) are associative and commutative, Polars can calculate them partially on each chunk and then combine them at the very end.

Returns (min, max, mean, std_dev)

§Errors

Will return Err if the parameter is not found or stats calculation fails

Source

pub fn apply_arcsinh_transform( &self, parameter_name: &str, cofactor: f32, ) -> Result<Arc<DataFrame>>

Apply arcsinh transformation to a parameter using Polars This is the most common transformation for flow cytometry data Formula: arcsinh(x / cofactor) / ln(10)

§Arguments
  • parameter_name - Name of the parameter to transform
  • cofactor - Scaling factor (typical: 150-200 for modern instruments)
§Returns

New DataFrame with the transformed parameter

Source

pub fn apply_arcsinh_transforms( &self, parameters: &[(&str, f32)], ) -> Result<Arc<DataFrame>>

Apply arcsinh transformation to multiple parameters

§Arguments
  • parameters - List of (parameter_name, cofactor) pairs
§Returns

New DataFrame with all specified parameters transformed

Source

pub fn apply_default_arcsinh_transform(&self) -> Result<Arc<DataFrame>>

Apply default arcsinh transformation to all fluorescence parameters Automatically detects fluorescence parameters (excludes FSC, SSC, Time) Uses cofactor = 200 (good default for modern instruments)

Source

pub fn get_spillover_matrix(&self) -> Result<Option<(Array2<f32>, Vec<String>)>>

Extract compensation matrix from $SPILLOVER keyword Returns (matrix, channel_names) if spillover keyword exists Returns None if no spillover keyword is present in the file

§Returns

Some((compensation_matrix, channel_names)) if spillover exists, None otherwise

§Errors

Will return Err if spillover keyword is malformed

Source

pub fn has_compensation(&self) -> bool

Check if this file has compensation information

Source

pub fn apply_file_compensation(&self) -> Result<Arc<DataFrame>>

Apply compensation from the file’s $SPILLOVER keyword Convenience method that extracts spillover and applies it automatically

§Returns

New DataFrame with compensated data, or error if no spillover keyword exists

Source

pub fn get_compensated_parameters( &self, channels_needed: &[&str], ) -> Result<HashMap<String, Vec<f32>>>

OPTIMIZED: Get compensated data for specific parameters only (lazy/partial compensation)

This is 15-30x faster than apply_file_compensation when you only need a few parameters because it:

  • Only compensates the requested channels (e.g., 2 vs 30)
  • Uses sparse matrix optimization for matrices with >80% zeros
  • Bypasses compensation entirely for identity matrices
§Arguments
  • channels_needed - Only the channel names you need compensated (typically 2 for a plot)
§Returns

HashMap of channel_name -> compensated data (as Vec)

§Performance
  • Dense matrix (2/30 channels): 15x faster (150ms → 10ms)
  • Sparse matrix (90% sparse): 50x faster (150ms → 3ms)
  • Identity matrix: 300x faster (150ms → 0.5ms)
Source

pub fn apply_compensation( &self, compensation_matrix: &Array2<f32>, channel_names: &[&str], ) -> Result<Arc<DataFrame>>

Apply compensation matrix to the data using Polars Compensation corrects for spectral overlap between fluorescence channels

§Arguments
  • compensation_matrix - 2D matrix where element [i,j] represents spillover from channel j into channel i
  • channel_names - Names of channels in the order they appear in the matrix
§Returns

New DataFrame with compensated fluorescence values

§Example
// Create a 3x3 compensation matrix
let comp_matrix = Array2::from_shape_vec((3, 3), vec![
    1.0, 0.1, 0.05,  // FL1-A compensation
    0.2, 1.0, 0.1,   // FL2-A compensation
    0.1, 0.15, 1.0,  // FL3-A compensation
]).unwrap();
let channels = vec!["FL1-A", "FL2-A", "FL3-A"];
let compensated = fcs.apply_compensation(&comp_matrix, &channels)?;
Source

pub fn apply_spectral_unmixing( &self, unmixing_matrix: &Array2<f32>, channel_names: &[&str], cofactor: Option<f32>, ) -> Result<Arc<DataFrame>>

Apply spectral unmixing (similar to compensation but for spectral flow cytometry) Uses a good default cofactor of 200 for transformation before/after unmixing

§Arguments
  • unmixing_matrix - Matrix describing spectral signatures of fluorophores
  • channel_names - Names of spectral channels
  • cofactor - Cofactor for arcsinh transformation (default: 200)
§Returns

New DataFrame with unmixed and transformed fluorescence values

Trait Implementations§

Source§

impl Clone for Fcs

Source§

fn clone(&self) -> Fcs

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Fcs

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl Freeze for Fcs

§

impl !RefUnwindSafe for Fcs

§

impl Send for Fcs

§

impl Sync for Fcs

§

impl Unpin for Fcs

§

impl !UnwindSafe for Fcs

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Key for T
where T: Clone,

Source§

fn align() -> usize

The alignment necessary for the key. Must return a power of two.
Source§

fn size(&self) -> usize

The size of the key in bytes.
Source§

unsafe fn init(&self, ptr: *mut u8)

Initialize the key in the given memory location. Read more
Source§

unsafe fn get<'a>(ptr: *const u8) -> &'a T

Get a reference to the key from the given memory location. Read more
Source§

unsafe fn drop_in_place(ptr: *mut u8)

Drop the key in place. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> PlanCallbackArgs for T

Source§

impl<T> PlanCallbackOut for T