Skip to content

Commit

Permalink
analyte_fn => analytetype, table_type => tabletype, .sample not restr…
Browse files Browse the repository at this point in the history
…icted to string, cal_range => dynamic_range
  • Loading branch information
yufongpeng committed Dec 14, 2023
1 parent ddd4e95 commit 16a133c
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 117 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ This package provides two basic wrappers, `ColumnDataTable{A, T}` and `RowDataTa
|`sample`|`Vector{String}`, strings transformed from column `samplecol`.|`Vector{String}`, the column names that are sample names..|
|`table`|Tabular data of type `T`|same|

`ColumnDataTable` can be created by `ColumnDataTable(table, samplecol; analyte_fn, analyte_name)`. By default, `analyte_name` includes all properties of `table` without `samplecol`. `RowDataTable` can be created by `RowDataTable(table, analytecol; analyte_fn, sample_name)`. By default, `sample_name` includes all properties of `table` without `analytecol`.
To add new samples to `ColumnDataTable{A, T}`, user can directly modify `table`; for `RowDataTable{A, T}`, user have to modify `samplename` as well. To add new analytes, user can directly modify `table`, and modify `analyte`.
`ColumnDataTable` can be created by `ColumnDataTable(table, samplecol; analytetype, analytename)`. By default, `analytename` includes all properties of `table` without `samplecol`. `RowDataTable` can be created by `RowDataTable(table, analytecol; analytetype, samplename)`. By default, `samplename` includes all properties of `table` without `analytecol`.
To add new samples to `ColumnDataTable{A, T}`, user can directly modify `table`; for `RowDataTable{A, T}`, user have to modify `samplename` as well. To add new analytes, user can directly modify `table` for `RowDataTable{A, T}`, and additionally modify `analyte` for `ColumnDataTable{A, T}`.

The package provides another two wrappers, `MethodTable{A, T}`, and `AnalysisTable{A, T} <: AbstractAnalysisTable{A, T}`.
### MethodTable
Expand Down Expand Up @@ -208,12 +208,12 @@ It can contain multiple `*.dt`. The file names must start from an integer, `_` a
### Reading and writing Batch
To read a batch into julia, call `ChemistryQuantitativeAnalysis.read`.
```julia-repl
julia> ChemistryQuantitativeAnalysis.read("batch_name.batch", T; table_type, analyte_fn)
julia> ChemistryQuantitativeAnalysis.read("batch_name.batch", T; table_type, analytetype)
```
`T` is the sink function for tabular data; it should create an object following `Tables.jl` interface. `table_type` is `T` parameter in the type signature of `Batch` which determines the underlying table type, and `analyte_fn` is responsible for converting `analyte` in string type into user defined type `A`.
`T` is the sink function for tabular data; it should create an object following `Tables.jl` interface. `table_type` is `T` parameter in the type signature of `Batch` which determines the underlying table type, and `analytetype` is a concrete type for `analyte` which msut have a method for string input.

To write project to disk, call `ChemistryQuantitativeAnalysis.write`. There is a keyword argument `delim` controling whether using "\t" or "," as delim for tables.
```julia-repl
julia> ChemistryQuantitativeAnalysis.write("batch_name.pjc", batch; delim = "\t")
```
A new folder `calibration` containing multiple `*.mcal` or `*.scal` folders. The former is for `MultipleCalibration` and the latter is for `SingleCalibration`.
There will be a folder `calibration` containing multiple `*.mcal` or `*.scal` folders. The former is for `MultipleCalibration` and the latter is for `SingleCalibration`.
87 changes: 45 additions & 42 deletions src/ChemistryQuantitativeAnalysis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export MultipleCalibration, SingleCalibration,
ColumnDataTable, RowDataTable, AnalysisTable, MethodTable,
Batch, calibration, update_calibration!,
read_calibration, read_datatable, read_analysistable, read_methodtable, read_batch,
cal_range, lloq, uloq, accuracy, accuracy!, set_accuracy, set_accuracy!, update_accuracy!,
dynamic_range, lloq, uloq, accuracy, accuracy!, set_accuracy, set_accuracy!, update_accuracy!,
inv_predict, inv_predict!, inv_predict_accuracy!, set_inv_predict, set_inv_predict!, update_inv_predict!,
relative_signal, set_relative_signal, set_relative_signal!, update_relative_signal!,
quantification, quantification!, set_quantification, set_quantification!, update_quantification!,
Expand All @@ -32,7 +32,7 @@ Tabular data wrapper indicates part of columns represent analytes, and all rows
# Properties
* `analytename`: `Vector{Symbol}`, the column names of `table` that are analyte names.
* `samplename`: `Vector{Symbol}`, sample names in type symbol.
* `sample`: `Vector{String}`, sample names in type string.
* `sample`: `Vector`, sample names.
"""
struct ColumnDataTable{A, T} <: AbstractDataTable{A, T}
analyte::Vector{A}
Expand All @@ -41,22 +41,25 @@ struct ColumnDataTable{A, T} <: AbstractDataTable{A, T}
end

"""
ColumnDataTable(analyte_name::Vector{Symbol}, samplecol::Symbol, table; analyte_fn = default_analyte_fn)
ColumnDataTable(samplecol::Symbol, table; analyte_name = setdiff(propertynames(table), [samplecol]), analyte_fn = default_analyte_fn)
ColumnDataTable(table, samplecol::Symbol; analyte_name = setdiff(propertynames(table), [samplecol]), analyte_fn = default_analyte_fn)
ColumnDataTable(analytename::Vector{Symbol}, samplecol::Symbol, table; analytetype = String)
ColumnDataTable(samplecol::Symbol, table; analytename = setdiff(propertynames(table), [samplecol]), analytetype = String)
ColumnDataTable(table, samplecol::Symbol; analytename = setdiff(propertynames(table), [samplecol]), analytetype = String)
User-friendly contructors for `ColumnDataTable`. See the documentation of the type for detail description.
User-friendly contructors for `ColumnDataTable`.
* `analytename`
* `samplecol`
"""
ColumnDataTable(analyte_name::Vector{Symbol}, samplecol::Symbol, table; analyte_fn = default_analyte_fn) =
ColumnDataTable(analyte_fn.(string.(analyte_name)), samplecol, table)
ColumnDataTable(samplecol::Symbol, table; analyte_name = setdiff(propertynames(table), [samplecol]), analyte_fn = default_analyte_fn) =
ColumnDataTable(analyte_name, samplecol, table; analyte_fn)
ColumnDataTable(table, samplecol::Symbol; analyte_name = setdiff(propertynames(table), [samplecol]), analyte_fn = default_analyte_fn) =
ColumnDataTable(analyte_name, samplecol, table; analyte_fn)
ColumnDataTable(analytename::Vector{Symbol}, samplecol::Symbol, table; analytetype = String) =
ColumnDataTable(analytetype.(string.(analytename)), samplecol, table)
ColumnDataTable(samplecol::Symbol, table; analytename = setdiff(propertynames(table), [samplecol]), analytetype = String) =
ColumnDataTable(analytename, samplecol, table; analytetype)
ColumnDataTable(table, samplecol::Symbol; analytename = setdiff(propertynames(table), [samplecol]), analytetype = String) =
ColumnDataTable(analytename, samplecol, table; analytetype)

function getproperty(tbl::ColumnDataTable, property::Symbol)
if property == :sample
string.(getproperty(tbl.table, tbl.samplecol))
getproperty(tbl.table, tbl.samplecol)
elseif property == :samplename
Symbol.(getproperty(tbl.table, tbl.samplecol))
elseif property == :analytename
Expand All @@ -81,36 +84,36 @@ Tabular data wrapper indicates part of columns represent analyte, and all rows r
# Properties
* `analytename`: `Symbol`, the column name that each element is analyte name.
* `sample`: `Vector{String}`, sample names in type string.
* `sample`: `Vector{Symbol}`, identical to `samplename`.
"""
struct RowDataTable{A, T} <: AbstractDataTable{A, T}
analyte::Vector{A}
analytecol::Symbol
samplename::Vector{Symbol}
table::T
function RowDataTable(analyte::Vector{A}, analytecol::Symbol, sample_name::Vector{Symbol}, table::T) where {A, T}
function RowDataTable(analyte::Vector{A}, analytecol::Symbol, samplename::Vector{Symbol}, table::T) where {A, T}
length(analyte) == length(getproperty(table, analytecol)) || throw(ArgumentError("The length of `analyte` is different from that of `table`."))
new{A, T}(analyte, analytecol, sample_name, table)
new{A, T}(analyte, analytecol, samplename, table)
end
end

"""
RowDataTable(analytecol::Symbol, sample_name::Vector{Symbol}, table; analyte_fn = default_analyte_fn)
RowDataTable(analytecol::Symbol, table; sample_name = setdiff(propertynames(table), [analytecol]), analyte_fn = default_analyte_fn)
RowDataTable(table, analytecol::Symbol; sample_name = setdiff(propertynames(table), [analytecol]), analyte_fn = default_analyte_fn)
RowDataTable(analytecol::Symbol, samplename::Vector{Symbol}, table; analytetype = String)
RowDataTable(analytecol::Symbol, table; samplename = setdiff(propertynames(table), [analytecol]), analytetype = String)
RowDataTable(table, analytecol::Symbol; samplename = setdiff(propertynames(table), [analytecol]), analytetype = String)
User-friendly contructors for `RowDataTable`. See the documentation of the type for detail description.
"""
RowDataTable(analytecol::Symbol, sample_name::Vector{Symbol}, table; analyte_fn = default_analyte_fn) =
RowDataTable(analyte_fn.(string.(getproperty(table, analytecol))), analytecol, sample_name, table)
RowDataTable(analytecol::Symbol, table; sample_name = setdiff(propertynames(table), [analytecol]), analyte_fn = default_analyte_fn) =
RowDataTable(analytecol, sample_name, table; analyte_fn)
RowDataTable(table, analytecol::Symbol; sample_name = setdiff(propertynames(table), [analytecol]), analyte_fn = default_analyte_fn) =
RowDataTable(analytecol, sample_name, table; analyte_fn)
RowDataTable(analytecol::Symbol, samplename::Vector{Symbol}, table; analytetype = String) =
RowDataTable(analytetype.(string.(getproperty(table, analytecol))), analytecol, samplename, table)
RowDataTable(analytecol::Symbol, table; samplename = setdiff(propertynames(table), [analytecol]), analytetype = String) =
RowDataTable(analytecol, samplename, table; analytetype)
RowDataTable(table, analytecol::Symbol; samplename = setdiff(propertynames(table), [analytecol]), analytetype = String) =
RowDataTable(analytecol, samplename, table; analytetype)

function getproperty(tbl::RowDataTable{A}, property::Symbol) where A
if property == :sample
string.(getfield(tbl, :samplename))
getfield(tbl, :samplename)
elseif property == :analytename
Symbol.(getfield(tbl, :analyte))
elseif !in(property, fieldnames(RowDataTable))
Expand All @@ -127,7 +130,7 @@ Tabular data wrapper of multiple tables for analysis. `A` determines analyte typ
# Fields
* `analyte`: `Vector{A}`, analyte in user-defined types.
* `sample`: `Vector{String}`, sample names.
* `sample`: `Vector`, sample names.
* `tables`: `Dictionary{Symbol, <: AbstractDataTable{A, <: T}}`, a dictionary mapping data type to datatable.
# Properties
Expand All @@ -139,10 +142,10 @@ All keys of `tables` are available.
"""
struct AnalysisTable{A, T} <: AbstractAnalysisTable{A, T}
analyte::Vector{A}
sample::Vector{String}
sample::Vector
tables::Dictionary{Symbol, <: AbstractDataTable{A}}
AnalysisTable(analyte::Vector{A}, sample::Vector{String}, tables::Dictionary{Symbol, <: AbstractDataTable{A, T}}) where {A, T} = new{A, T}(analyte, sample, tables)
AnalysisTable{T}(analyte::Vector{A}, sample::Vector{String}, tables::Dictionary{Symbol, <: AbstractDataTable{A, <: T}}) where {A, T} = new{A, T}(analyte, sample, tables)
AnalysisTable(analyte::Vector{A}, sample::Vector, tables::Dictionary{Symbol, <: AbstractDataTable{A, T}}) where {A, T} = new{A, T}(analyte, sample, tables)
AnalysisTable{T}(analyte::Vector{A}, sample::Vector, tables::Dictionary{Symbol, <: AbstractDataTable{A, <: T}}) where {A, T} = new{A, T}(analyte, sample, tables)
end

"""
Expand Down Expand Up @@ -442,23 +445,23 @@ include("cal.jl")
include("io.jl")

"""
ColumnDataTable(tbl::RowDataTable{A, T}, sample_name::Symbol) where {A, T}
ColumnDataTable{S}(tbl::RowDataTable{A, T}, sample_name::Symbol) where {A, S, T}
ColumnDataTable(tbl::RowDataTable{A, T}, samplecol::Symbol) where {A, T}
ColumnDataTable{S}(tbl::RowDataTable{A, T}, samplecol::Symbol) where {A, S, T}
Convert `RowDataTable` to `ColumnDataTable` with `sample_name` as the column name of sample. `S` must be provided if `T` is not a valid constructor.
Convert `RowDataTable` to `ColumnDataTable` with `samplecol` as the column name of sample. `S` must be provided if `T` is not a valid constructor.
"""
ColumnDataTable(tbl::RowDataTable{A, T}, sample_name::Symbol) where {A, T} = ColumnDataTable{T}(tbl, sample_name)
ColumnDataTable{T}(tbl::RowDataTable{A}, sample_name::Symbol) where {A, T} =
ColumnDataTable{T}(tbl.analyte, sample_name, T((; (sample_name => tbl.sample, (tbl.analytename .=> getanalyte.(Ref(tbl), tbl.analyte))...)...)))
ColumnDataTable(tbl::RowDataTable{A, T}, samplecol::Symbol) where {A, T} = ColumnDataTable{T}(tbl, samplecol)
ColumnDataTable{T}(tbl::RowDataTable{A}, samplecol::Symbol) where {A, T} =
ColumnDataTable{T}(tbl.analyte, samplecol, T((; (samplecol => tbl.sample, (tbl.analytename .=> getanalyte.(Ref(tbl), tbl.analytename))...)...)))

"""
RowDataTable(tbl::RowDataTable{A, T}, sample_name::Symbol) where {A, T}
RowDataTable{S}(tbl::RowDataTable{A, T}, sample_name::Symbol) where {A, S, T}
RowDataTable(tbl::RowDataTable{A, T}, analytecol::Symbol) where {A, T}
RowDataTable{S}(tbl::RowDataTable{A, T}, analytecol::Symbol) where {A, S, T}
Convert `RowDataTable` to `ColumnDataTable` with `sample_name` as the column name of sample. `S` must be provided if `T` is not a valid constructor.
Convert `RowDataTable` to `ColumnDataTable` with `analytecol` as the column name of sample. `S` must be provided if `T` is not a valid constructor.
"""
RowDataTable(tbl::ColumnDataTable{A, T}, analyte_name::Symbol) where {A, T} = RowDataTable{T}(tbl, analyte_name)
RowDataTable{T}(tbl::ColumnDataTable{A}, analyte_name::Symbol) where {A, T} =
RowDataTable{T}(tbl.analyte, tbl.samplename, T((; (analyte_name => string.(tbl.analytename), (tbl.samplename .=> getsample.(Ref(tbl), tbl.samplename))...)...)))
RowDataTable(tbl::ColumnDataTable{A, T}, analytecol::Symbol) where {A, T} = RowDataTable{T}(tbl, analytecol)
RowDataTable{T}(tbl::ColumnDataTable{A}, analytecol::Symbol) where {A, T} =
RowDataTable{T}(tbl.analyte, tbl.samplename, T((; (analytecol => tbl.analyte, (tbl.samplename .=> getsample.(Ref(tbl), tbl.samplename))...)...)))

end
Loading

0 comments on commit 16a133c

Please sign in to comment.