CHESSParsers API Reference
CHESSParsers reads instrument export files, such as plate-reader spreadsheets and incubator logs, into LabwareReads and EnvironmentLogs. It is not re-exported by CHESS; load it with using CHESSParsers. See Parsing Instrument Files for worked examples.
The functions most code uses are parse_instrument_file, which auto-detects the file's format, and record_reads!, which records a parsed read onto a CHESSCore labware (it lives in a package extension that loads with CHESSCore). New formats implement the InstrumentFormat interface and are added with register_format!.
CHESSParsers.format_registry — Constant
format_registryGlobal registry of known InstrumentFormat subtypes, keyed by name. Use register_format! to add to it and keys(format_registry) to see what's available.
CHESSParsers.BioSpaFormat — Type
struct BioSpaFormat <: InstrumentFormat endExport format for the BioTek/Agilent BioSpa automated incubator's .SES session file. See InstrumentFormat and EnvironmentLog (the chamber-level result type this format produces, distinct from the well-shaped LabwareRead the Gen5 formats produce).
CHESSParsers.CytationFormat — Type
struct CytationFormat <: InstrumentFormat endGen5 .xlsx export format for the BioTek Cytation plate reader/imager (e.g. Cytation5, Cytation10, CytationC10). See InstrumentFormat and _parse_gen5_workbook (shared by every Gen5-family format).
CHESSParsers.EnvironmentLog — Type
struct EnvironmentLog
metadata::Dict{String,Any}
data::DataFrame
endThe canonical result of parsing one reading kind of a chamber-level environmental log (e.g. a BioSpa incubator session's temperature/O2/CO2/humidity history) – data that has no well to attach to at all, unlike LabwareRead's per-plate-per-channel well measurements. A session logs several reading kinds at once; parse_raw/parse_instrument_file return one EnvironmentLog per kind, mirroring how LabwareRead splits by (plate, channel).
Fields:
metadata: everything constant for this one reading kind – at minimummetadata["format"],metadata["read_kind"](e.g."Temperature"; informational only, not a registeredCHESSCore.ReadKind), plus whatever else the format exposes (unit, setpoint, session start time, a plate slot/barcode mapping table, ...).data: a tidyDataFramewith exactly two columns –time::DateTime,value::Float64.
See also: DataFrame(::EnvironmentLog), environmentlog_to_json.
CHESSParsers.Epoch2Format — Type
struct Epoch2Format <: InstrumentFormat endGen5 .xlsx export format for the BioTek Epoch2 plate reader. See InstrumentFormat and _parse_gen5_workbook (shared by every Gen5-family format).
CHESSParsers.InstrumentFormat — Type
abstract type InstrumentFormat endDispatch tag for a specific instrument export format (e.g. an Epoch2 plate-reader export, a BioSpa incubator export). Every concrete format is a singleton struct subtyping this and implements two extension-point functions:
detect(::Type{T}, path::AbstractString) -> Bool: sniff-test whetherpathlooks like aTexport, used bydetect_formatfor auto-detection.parse_raw(::Type{T}, path::AbstractString; kwargs...) -> Vector{LabwareRead}: parsepathinto the package's canonicalLabwareReadrepresentation, one per (plate, channel) found in the file.
Register a new format with register_format! so it participates in both auto-detection and name-based lookup (see parse_instrument_file).
CHESSParsers.LabwareRead — Type
struct LabwareRead
metadata::Dict{String,Any}
data::DataFrame
endThe canonical, instrument-agnostic result of parsing one channel of one plate from an instrument export file – a channel being one specific measurement configuration (e.g. absorbance at a given wavelength, or fluorescence at a given excitation/emission pair). A single export file commonly contains multiple plates and/or multiple channels per plate; parse_raw/ parse_instrument_file return a Vector{LabwareRead}, one per (plate, channel) combination, rather than trying to force everything into one wide table. This is the seam that keeps the rest of the package (DataFrame/CHESS-object/JSON conversion) generic regardless of the instrument.
Fields:
metadata: everything that's constant for this one (plate, channel) – at minimummetadata["format"](theInstrumentFormatsubtype that produced it),metadata["plate"], andmetadata["read_kind"](e.g."Absorbance"/"Fluorescence", matching an already-registeredCHESSCore.ReadKindname), plus whatever else the format exposes (instrument serial, protocol name, export datetime, a channel's wavelength or excitation/emission, ...).data: a tidyDataFramewith exactly three columns –well::String,time::DateTime,value::Float64– one row per well per timepoint (a single row for an endpoint/non-kinetic read).
See also: DataFrame(::LabwareRead), record_reads!, labwareread_to_json.
CHESSParsers.SynergyFormat — Type
struct SynergyFormat <: InstrumentFormat endGen5 .xlsx export format for the BioTek Synergy plate reader (e.g. Synergy H1). See InstrumentFormat and _parse_gen5_workbook (shared by every Gen5-family format).
CHESSParsers.Take3TrioFormat — Type
struct Take3TrioFormat <: InstrumentFormat endExport format for the BioTek Take3 Trio nucleic-acid quant accessory's .xlsx export. See InstrumentFormat and LabwareRead.
DataFrames.DataFrame — Method
DataFrame(el::EnvironmentLog) -> DataFrameReturn the time/value table underlying el. Metadata (reading kind, unit, plate mapping, ...) is not included – see el.metadata for that.
DataFrames.DataFrame — Method
DataFrame(lr::LabwareRead) -> DataFrameReturn the tidy, long-format measurement table underlying lr. Metadata (instrument, protocol, export datetime, ...) is not included – see lr.metadata for that.
CHESSParsers._biospa_plates — Method
_biospa_plates(session) -> DataFrameParse <Plates><PlateDetails> into a table with columns id (real barcode), slot, experiment_name, and gen5_plate_number – the mapping a linked Gen5 .xlsx export alone can't always provide (its own sheets are sometimes named by Gen5's internal plate number, not the barcode).
CHESSParsers._gen5_channel_meta — Method
_gen5_channel_meta(label_cell) -> Union{Dict{String,Any},Nothing}Parse a raw data block's trailing marker into channel metadata: read_kind plus either wavelength or excitation/emission. Two shapes are recognized:
- a
"<name>:<label>"string (e.g."OD600:600","Fluor:505,536") – label is a bare integer (Absorbance wavelength) or a comma-separated pair (Fluorescence excitation,emission); - a bare
Real(e.g.500) – some endpoint exports label each row with just the wavelength and no name/colon at all; since there's no way to spell an excitation/emission pair without a separator, a bare number can only mean a single Absorbance wavelength.
Returns nothing if label_cell doesn't match either shape – the caller's job to skip such a row rather than error, since that's how a computed summary block (not a raw channel) is recognized.
CHESSParsers._gen5_reader_type — Method
_gen5_reader_type(path::AbstractString) -> Union{String,Nothing}Return the value of the first real plate sheet's "Reader Type:" field (e.g. "Epoch 2", "CytationC10"), or nothing if path isn't a readable Gen5 export. Used by every Gen5-family format's detect.
CHESSParsers._parse_gen5_workbook — Method
_parse_gen5_workbook(T::Type{<:InstrumentFormat}, path::AbstractString) -> Vector{LabwareRead}Parse every real plate sheet (skipping any companion pivot/summary sheets) of a Gen5 .xlsx export at path into one LabwareRead per (plate, channel), each tagged with metadata["format"] = T. Shared by Epoch2Format, SynergyFormat, and CytationFormat.
CHESSParsers.detect — Function
detect(::Type{T}, path::AbstractString) where T<:InstrumentFormat -> BoolReturn true if the file at path looks like a T export. Every concrete InstrumentFormat must implement this method; there is no fallback.
CHESSParsers.detect_format — Method
detect_format(path::AbstractString) -> Union{DataType,Nothing}Try every registered InstrumentFormat subtype's detect method against path, returning the first match, or nothing if none match.
CHESSParsers.environmentlog_to_json — Method
environmentlog_to_json(el::EnvironmentLog) -> StringSerialize el to a JSON string, the EnvironmentLog counterpart of labwareread_to_json (including its metadata["plates"] table).
CHESSParsers.json_to_environmentlog — Method
json_to_environmentlog(j::AbstractString) -> EnvironmentLogDeserialize a JSON string produced by environmentlog_to_json back into an EnvironmentLog.
CHESSParsers.json_to_labwareread — Method
json_to_labwareread(j::AbstractString) -> LabwareReadDeserialize a JSON string produced by labwareread_to_json back into a LabwareRead.
CHESSParsers.labwareread_to_json — Method
labwareread_to_json(lr::LabwareRead) -> StringSerialize lr to a JSON string. metadata["format"], if it holds an InstrumentFormat subtype, is lowered to its type name (a String) so the result is plain JSON.
CHESSParsers.parse_instrument_file — Method
parse_instrument_file(path::AbstractString; format=nothing, kwargs...) -> Vector{LabwareRead}Parse the instrument export file at path into one LabwareRead per (plate, channel) found in it.
format selects which InstrumentFormat to use:
nothing(default): auto-detect viadetect_format, erroring if no registered format matches.- a
String: looked up by name informat_registry. - an
InstrumentFormatsubtype: used directly, skipping detection.
Any kwargs are forwarded to the concrete format's parse_raw method.
CHESSParsers.parse_raw — Function
parse_raw(::Type{T}, path::AbstractString; kwargs...) where T<:InstrumentFormat -> VectorParse the file at path, known to be a T export, into a vector of result objects – one LabwareRead per (plate, channel) for the well-shaped Gen5 formats, or one EnvironmentLog per reading kind for chamber-level formats like BioSpaFormat that have no per-well data at all. Every concrete InstrumentFormat must implement this method; there is no fallback.
CHESSParsers.parse_raw — Method
parse_raw(::Type{BioSpaFormat}, path::AbstractString; kwargs...) -> Vector{EnvironmentLog}Parse a BioSpa .SES session file into one EnvironmentLog per reading kind (Temperature/O2/CO2/Humidity), each sharing the same time vector and the session's plate slot/barcode mapping (metadata["plates"]).
CHESSParsers.parse_raw — Method
parse_raw(::Type{Take3TrioFormat}, path::AbstractString; kwargs...) -> Vector{LabwareRead}Parse a Take3 Trio nucleic-acid quant .xlsx export into one LabwareRead per (sheet, channel): Absorbance@260/280/320 for the "Blank Read" sheet (real well IDs), and Absorbance@260/280 plus Concentration (ng/µL) for each "Sample Read #N" sheet (Gen5 SPL# sample tokens, not real wells – mapping a sample back to its physical source plate/well is the caller's responsibility, not something this file records).
CHESSParsers.record_reads! — Function
record_reads!(labware::CHESSCore.Labware, lr::LabwareRead; well_map=identity, instrument=nothing, layout=nothing)
record_reads!(labware::CHESSCore.Labware, lrs::Vector{LabwareRead}; kwargs...)Record every row of lr.data (or every LabwareRead in lrs, e.g. the result of parse_instrument_file) onto labware as a CHESSCore.Read, via CHESSCore.record_read!. lr.data has well, time, and value columns; lr.metadata["read_kind"] (constant for the whole LabwareRead) must already be a registered ReadKind (see CHESSCore.read_kinds, populated by e.g. CHESSLabConstants).
well_map converts a row's well value to the well name used in labware (identity by default, e.g. pass a function if the instrument's well-naming convention differs from labware's). instrument is forwarded to record_read! for capability checking.
layout, if given, is a CHESSExperiments.Experiment's :layout metadata DataFrame (one row per well, with a well column and a per-well metadata::Dict{Symbol,Any} column). The rest of lr.metadata (everything but "read_kind", which is already consumed structurally as a ReadKind) is merged into the matching row's metadata, namespaced under "chessparsers." – otherwise this would be silently dropped on the way into CHESSCore since Read has nowhere to carry free-form metadata; a layout row's metadata is the intended carrier for it. Wells with no matching row in layout are recorded as before, without attaching metadata anywhere.
A design's layout can span multiple plates, and well names (e.g. "A1") repeat across them – when layout has a labware column, rows are matched on (labware, well) (labware compared against CHESSCore.name(labware), this call's own labware argument), not well alone, so metadata never lands on the wrong plate's row. Layouts without a labware column fall back to matching on well only.
Returns labware.
Provided by the CHESSCore package extension (using CHESSCore activates it) – CHESSParsers itself has no dependency on CHESSCore, so this function has no methods until then. Recording also needs CHESSCore.read_kinds to already contain whatever lr.metadata["read_kind"] names, which is the caller's responsibility (typically via using CHESSLabConstants or another package that registers the relevant ReadKinds) – CHESSParsers doesn't register any itself.
CHESSParsers.register_format! — Method
register_format!(T::Type{<:InstrumentFormat}; name::AbstractString, override::Bool=false)Register T in the global format_registry under name, making it discoverable via format_registry["name"] and usable by name in parse_instrument_file.
Errors if name is already registered unless override=true (in which case the previous entry is replaced and a warning is emitted) – this guards against two independently-authored instrument packages accidentally colliding on the same name.
Third-party instrument packages should call this once per InstrumentFormat they define, typically at module top-level, right after using CHESSParsers.
Examples
julia> struct ExFormat <: InstrumentFormat end
julia> CHESSParsers.detect(::Type{ExFormat}, path) = endswith(path, ".ex");
julia> register_format!(ExFormat; name="ex_format");
julia> haskey(format_registry, "ex_format")
true