Skip to content

Commit 9f11b5f

Browse files
committed
add run spreadsheet parser and tests
1 parent 36e0407 commit 9f11b5f

9 files changed

Lines changed: 576 additions & 7 deletions

File tree

src/Core/ArcTypes.fs

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1423,7 +1423,6 @@ type ArcWorkflow(identifier : string, ?title : string, ?description : string, ?w
14231423
HashCodes.boxHashSeq this.SubWorkflowIdentifiers
14241424
HashCodes.boxHashSeq this.Parameters
14251425
HashCodes.boxHashSeq this.Components
1426-
HashCodes.boxHashOption this.DataMap
14271426
HashCodes.boxHashSeq this.Contacts
14281427
HashCodes.boxHashSeq this.Comments
14291428
|]
@@ -1433,11 +1432,12 @@ type ArcWorkflow(identifier : string, ?title : string, ?description : string, ?w
14331432

14341433

14351434
[<AttachMembers>]
1436-
type ArcRun(identifier: string, ?title : string, ?description : string, ?measurementType : OntologyAnnotation, ?technologyType : OntologyAnnotation, ?technologyPlatform : OntologyAnnotation, ?tables: ResizeArray<ArcTable>, ?datamap : DataMap, ?performers : ResizeArray<Person>, ?comments : ResizeArray<Comment>) =
1435+
type ArcRun(identifier: string, ?title : string, ?description : string, ?measurementType : OntologyAnnotation, ?technologyType : OntologyAnnotation, ?technologyPlatform : OntologyAnnotation, ?workflowIdentifiers : ResizeArray<string>, ?tables: ResizeArray<ArcTable>, ?datamap : DataMap, ?performers : ResizeArray<Person>, ?comments : ResizeArray<Comment>) =
14371436
inherit ArcTables(defaultArg tables <| ResizeArray())
14381437

14391438
let performers = defaultArg performers <| ResizeArray()
14401439
let comments = defaultArg comments <| ResizeArray()
1440+
let workflowIdentifiers = defaultArg workflowIdentifiers <| ResizeArray()
14411441
let mutable identifier : string =
14421442
let identifier = identifier.Trim()
14431443
Helper.Identifier.checkValidCharacters identifier
@@ -1448,6 +1448,7 @@ type ArcRun(identifier: string, ?title : string, ?description : string, ?measure
14481448
let mutable measurementType : OntologyAnnotation option = measurementType
14491449
let mutable technologyType : OntologyAnnotation option = technologyType
14501450
let mutable technologyPlatform : OntologyAnnotation option = technologyPlatform
1451+
let mutable workflowIdentifiers : ResizeArray<string> = workflowIdentifiers
14511452
let mutable dataMap : DataMap option = datamap
14521453
let mutable performers = performers
14531454
let mutable comments = comments
@@ -1462,14 +1463,15 @@ type ArcRun(identifier: string, ?title : string, ?description : string, ?measure
14621463
member this.MeasurementType with get() = measurementType and set(n) = measurementType <- n
14631464
member this.TechnologyType with get() = technologyType and set(n) = technologyType <- n
14641465
member this.TechnologyPlatform with get() = technologyPlatform and set(n) = technologyPlatform <- n
1466+
member this.WorkflowIdentifiers with get() = workflowIdentifiers and set(w) = workflowIdentifiers <- w
14651467
member this.DataMap with get() = dataMap and set(n) = dataMap <- n
14661468
member this.Performers with get() = performers and set(n) = performers <- n
14671469
member this.Comments with get() = comments and set(n) = comments <- n
14681470
member this.StaticHash with get() = staticHash and set(h) = staticHash <- h
14691471

14701472
static member init (identifier : string) = ArcRun(identifier)
1471-
static member create (identifier: string, ?title : string, ?description : string, ?measurementType : OntologyAnnotation, ?technologyType : OntologyAnnotation, ?technologyPlatform : OntologyAnnotation, ?tables: ResizeArray<ArcTable>, ?datamap : DataMap, ?performers : ResizeArray<Person>, ?comments : ResizeArray<Comment>) =
1472-
ArcRun(identifier = identifier, ?title = title, ?description = description, ?measurementType = measurementType, ?technologyType = technologyType, ?technologyPlatform = technologyPlatform, ?tables =tables, ?datamap = datamap, ?performers = performers, ?comments = comments)
1473+
static member create (identifier: string, ?title : string, ?description : string, ?measurementType : OntologyAnnotation, ?technologyType : OntologyAnnotation, ?technologyPlatform : OntologyAnnotation, ?workflowIdentifiers : ResizeArray<string>, ?tables: ResizeArray<ArcTable>, ?datamap : DataMap, ?performers : ResizeArray<Person>, ?comments : ResizeArray<Comment>) =
1474+
ArcRun(identifier = identifier, ?title = title, ?description = description, ?measurementType = measurementType, ?technologyType = technologyType, ?technologyPlatform = technologyPlatform, ?workflowIdentifiers = workflowIdentifiers, ?tables =tables, ?datamap = datamap, ?performers = performers, ?comments = comments)
14731475

14741476
static member make
14751477
(identifier : string)
@@ -1478,14 +1480,38 @@ type ArcRun(identifier: string, ?title : string, ?description : string, ?measure
14781480
(measurementType : OntologyAnnotation option)
14791481
(technologyType : OntologyAnnotation option)
14801482
(technologyPlatform : OntologyAnnotation option)
1483+
(workflowIdentifiers : ResizeArray<string>)
14811484
(tables : ResizeArray<ArcTable>)
14821485
(datamap : DataMap option)
14831486
(performers : ResizeArray<Person>)
14841487
(comments : ResizeArray<Comment>) =
1485-
ArcRun(identifier = identifier, ?title = title, ?description = description, ?measurementType = measurementType, ?technologyType = technologyType, ?technologyPlatform = technologyPlatform, tables =tables, ?datamap = datamap, performers = performers, comments = comments)
1488+
ArcRun(identifier = identifier, ?title = title, ?description = description, ?measurementType = measurementType, ?technologyType = technologyType, ?technologyPlatform = technologyPlatform, workflowIdentifiers = workflowIdentifiers, tables =tables, ?datamap = datamap, performers = performers, comments = comments)
14861489

14871490
static member FileName = ARCtrl.ArcPathHelper.RunFileName
1488-
1491+
1492+
/// Returns the count of workflow *identifiers*. This is not necessarily the same as the count of workflows, as not all identifiers correspond to an existing workflow.
1493+
member this.WorkflowIdentifierCount
1494+
with get() = this.WorkflowIdentifiers.Count
1495+
1496+
member this.WorkflowCount
1497+
with get() = this.Workflows.Count
1498+
1499+
/// Returns all workflows registered in this run, that correspond to an existing workflow object in the associated investigation.
1500+
member this.Workflows
1501+
with get(): ResizeArray<ArcWorkflow> =
1502+
let inv = ArcTypesAux.SanityChecks.validateRegisteredInvestigation this.Investigation
1503+
this.WorkflowIdentifiers
1504+
|> Seq.choose inv.TryGetWorkflow
1505+
|> ResizeArray
1506+
1507+
/// Returns all registered workflow identifiers that do not correspond to an existing workflow object in the associated investigation.
1508+
member this.VacantWorkflowIdentifiers
1509+
with get() =
1510+
let inv = ArcTypesAux.SanityChecks.validateRegisteredInvestigation this.Investigation
1511+
this.WorkflowIdentifiers
1512+
|> Seq.filter (inv.ContainsWorkflow >> not)
1513+
|> ResizeArray
1514+
14891515
// - Table API - //
14901516
static member addTable(table:ArcTable, ?index: int) =
14911517
fun (run:ArcRun) ->
@@ -1715,13 +1741,15 @@ type ArcRun(identifier: string, ?title : string, ?description : string, ?measure
17151741
let nextComments = this.Comments |> ResizeArray.map (fun c -> c.Copy())
17161742
let nextDataMap = this.DataMap |> Option.map (fun d -> d.Copy())
17171743
let nextPerformers = this.Performers |> ResizeArray.map (fun c -> c.Copy())
1744+
let nextWorkflowIdentifiers = this.WorkflowIdentifiers |> ResizeArray.map (fun c -> c)
17181745
ArcRun.make
17191746
this.Identifier
17201747
this.Title
17211748
this.Description
17221749
this.MeasurementType
17231750
this.TechnologyType
17241751
this.TechnologyPlatform
1752+
nextWorkflowIdentifiers
17251753
nextTables
17261754
nextDataMap
17271755
nextPerformers
@@ -1747,6 +1775,11 @@ type ArcRun(identifier: string, ?title : string, ?description : string, ?measure
17471775
this.TechnologyType <- run.TechnologyType
17481776
if run.TechnologyPlatform.IsSome || updateAlways then
17491777
this.TechnologyPlatform <- run.TechnologyPlatform
1778+
if run.WorkflowIdentifiers.Count <> 0 || updateAlways then
1779+
let s = ArcTypesAux.updateAppendResizeArray appendSequences this.WorkflowIdentifiers run.WorkflowIdentifiers
1780+
this.WorkflowIdentifiers <- s
1781+
if run.DataMap.IsSome || updateAlways then
1782+
this.DataMap <- run.DataMap
17501783
if run.Tables.Count <> 0 || updateAlways then
17511784
let s = ArcTypesAux.updateAppendResizeArray appendSequences this.Tables run.Tables
17521785
this.Tables <- s
@@ -1767,6 +1800,8 @@ type ArcRun(identifier: string, ?title : string, ?description : string, ?measure
17671800
MeasurementType = %A,
17681801
TechnologyType = %A,
17691802
TechnologyPlatform = %A,
1803+
WorkflowIdentifiers = %A,
1804+
DataMap = %A,
17701805
Tables = %A,
17711806
Performers = %A,
17721807
Comments = %A
@@ -1777,6 +1812,8 @@ type ArcRun(identifier: string, ?title : string, ?description : string, ?measure
17771812
this.MeasurementType
17781813
this.TechnologyType
17791814
this.TechnologyPlatform
1815+
this.WorkflowIdentifiers
1816+
this.DataMap
17801817
this.Tables
17811818
this.Performers
17821819
this.Comments
@@ -1794,12 +1831,13 @@ type ArcRun(identifier: string, ?title : string, ?description : string, ?measure
17941831
let mst = this.MeasurementType = other.MeasurementType
17951832
let tt = this.TechnologyType = other.TechnologyType
17961833
let tp = this.TechnologyPlatform = other.TechnologyPlatform
1834+
let wf = Seq.compare this.WorkflowIdentifiers other.WorkflowIdentifiers
17971835
let dm = this.DataMap = other.DataMap
17981836
let tables = Seq.compare this.Tables other.Tables
17991837
let perf = Seq.compare this.Performers other.Performers
18001838
let comments = Seq.compare this.Comments other.Comments
18011839
// Todo maybe add reflection check to prove that all members are compared?
1802-
[|i; t; d; mst; tt; tp; dm; tables; perf; comments|] |> Seq.forall (fun x -> x = true)
1840+
[|i; t; d; mst; tt; tp; wf; dm; tables; perf; comments|] |> Seq.forall (fun x -> x = true)
18031841

18041842
/// <summary>
18051843
/// Use this function to check if this ArcRun and the input ArcRun refer to the same object.
@@ -1825,6 +1863,7 @@ type ArcRun(identifier: string, ?title : string, ?description : string, ?measure
18251863
HashCodes.boxHashOption this.MeasurementType
18261864
HashCodes.boxHashOption this.TechnologyType
18271865
HashCodes.boxHashOption this.TechnologyPlatform
1866+
HashCodes.boxHashSeq this.WorkflowIdentifiers
18281867
HashCodes.boxHashSeq this.Tables
18291868
HashCodes.boxHashSeq this.Performers
18301869
HashCodes.boxHashSeq this.Comments
@@ -1841,6 +1880,7 @@ type ArcRun(identifier: string, ?title : string, ?description : string, ?measure
18411880
HashCodes.boxHashOption this.TechnologyType
18421881
HashCodes.boxHashOption this.TechnologyPlatform
18431882
HashCodes.boxHashOption this.DataMap
1883+
HashCodes.boxHashSeq this.WorkflowIdentifiers
18441884
HashCodes.boxHashSeq this.Tables
18451885
HashCodes.boxHashSeq this.Performers
18461886
HashCodes.boxHashSeq this.Comments

src/Spreadsheet/ARCtrl.Spreadsheet.fsproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
<Compile Include="Metadata\Assays.fs" />
2323
<Compile Include="Metadata\Study.fs" />
2424
<Compile Include="Metadata\Workflow.fs" />
25+
<Compile Include="Metadata\Run.fs" />
2526
<Compile Include="Metadata\OntologySourceReference.fs" />
2627
<Compile Include="AnnotationTable\CompositeCell.fs" />
2728
<Compile Include="AnnotationTable\CompositeHeader.fs" />
@@ -34,6 +35,7 @@
3435
<Compile Include="ArcAssay.fs" />
3536
<Compile Include="ArcStudy.fs" />
3637
<Compile Include="ArcWorkflow.fs" />
38+
<Compile Include="ArcRun.fs" />
3739
<Compile Include="ArcInvestigation.fs" />
3840
<Compile Include="Template.fs" />
3941
</ItemGroup>

src/Spreadsheet/ArcRun.fs

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
namespace ARCtrl.Spreadsheet
2+
3+
open ARCtrl
4+
open ARCtrl.Helper
5+
open FsSpreadsheet
6+
7+
open Run
8+
9+
module ArcRun =
10+
11+
let [<Literal>] metadataSheetName = "isa_run"
12+
13+
let fromRows (rows : seq<SparseRow>) =
14+
15+
let en = rows.GetEnumerator()
16+
17+
let rec loop lastRow run performers rowNumber =
18+
19+
match lastRow with
20+
| Some prefix when prefix = runLabel ->
21+
let currentRow, rowNumber, _, run = Run.fromRows (rowNumber + 1) en
22+
loop currentRow (Some run) performers rowNumber
23+
24+
| Some prefix when prefix = performersLabel ->
25+
let currentLine, rowNumber, _, performers = Contacts.fromRows (Some performersLabelPrefix) (rowNumber + 1) en
26+
loop currentLine run performers rowNumber
27+
| _ ->
28+
match run, performers with
29+
| None, performers -> ArcRun.create(Identifier.createMissingIdentifier(), performers = ResizeArray performers)
30+
| Some run, performers ->
31+
run.Performers <- ResizeArray performers
32+
run
33+
34+
if en.MoveNext () then
35+
let currentLine = en.Current |> SparseRow.tryGetValueAt 0
36+
loop currentLine None [] 1
37+
38+
else
39+
failwith "empty run metadata sheet"
40+
41+
let toRows (run : ArcRun) =
42+
43+
seq {
44+
yield SparseRow.fromValues [runLabel]
45+
yield! toRows run
46+
47+
yield SparseRow.fromValues [performersLabel]
48+
yield! Contacts.toRows (Some performersLabelPrefix) (List.ofSeq run.Performers)
49+
}
50+
51+
let toMetadataSheet (run : ArcRun) : FsWorksheet =
52+
let sheet = FsWorksheet(metadataSheetName)
53+
run
54+
|> toRows
55+
|> Seq.iteri (fun rowI r -> SparseRow.writeToSheet (rowI + 1) r sheet)
56+
sheet
57+
58+
let fromMetadataSheet (sheet : FsWorksheet) : ArcRun =
59+
try
60+
let rows =
61+
sheet.Rows
62+
|> Seq.map SparseRow.fromFsRow
63+
//let hasPrefix =
64+
// rows
65+
// |> Seq.exists (fun row -> row |> Seq.head |> snd |> fun s -> s.StartsWith(assaysPrefix))
66+
rows
67+
|> fromRows
68+
with
69+
| err -> failwithf "Failed while parsing metadatasheet: %s" err.Message
70+
71+
let toMetadataCollection (run : ArcRun) =
72+
run
73+
|> toRows
74+
|> Seq.map (fun row -> SparseRow.getAllValues row)
75+
76+
let fromMetadataCollection (collection : seq<seq<string option>>) : ArcRun =
77+
try
78+
let rows =
79+
collection
80+
|> Seq.map SparseRow.fromAllValues
81+
rows
82+
|> fromRows
83+
with
84+
| err -> failwithf "Failed while parsing metadatasheet: %s" err.Message
85+
86+
let isMetadataSheetName (name : string) =
87+
name = metadataSheetName
88+
89+
let isMetadataSheet (sheet : FsWorksheet) =
90+
isMetadataSheetName sheet.Name
91+
92+
let tryGetMetadataSheet (doc : FsWorkbook) =
93+
doc.GetWorksheets()
94+
|> Seq.tryFind isMetadataSheet
95+
96+
[<AutoOpen>]
97+
module ArcRunExtensions =
98+
99+
type ArcRun with
100+
101+
/// Reads an run from a spreadsheet
102+
static member fromFsWorkbook (doc : FsWorkbook) : ArcRun =
103+
try
104+
// Reading the "Run" metadata sheet. Here metadata
105+
let runMetadata =
106+
match ArcRun.tryGetMetadataSheet doc with
107+
| Option.Some sheet ->
108+
ArcRun.fromMetadataSheet sheet
109+
| None ->
110+
printfn "Cannot retrieve metadata: Run file does not contain \"%s\" sheet." ArcRun.metadataSheetName
111+
ArcRun.create(Identifier.createMissingIdentifier())
112+
let sheets = doc.GetWorksheets()
113+
let annotationTables =
114+
sheets |> Seq.choose ArcTable.tryFromFsWorksheet
115+
let datamapSheet =
116+
sheets |> Seq.tryPick DataMapTable.tryFromFsWorksheet
117+
runMetadata.DataMap <- datamapSheet
118+
if annotationTables |> Seq.isEmpty |> not then
119+
runMetadata.Tables <- ResizeArray annotationTables
120+
runMetadata
121+
with
122+
| err -> failwithf "Could not parse assay: \n%s" err.Message
123+
124+
125+
/// <summary>
126+
/// Write a run to a spreadsheet
127+
/// </summary>
128+
/// <param name="run"></param>
129+
static member toFsWorkbook (run : ArcRun) =
130+
let doc = new FsWorkbook()
131+
let metadataSheet = ArcRun.toMetadataSheet (run)
132+
doc.AddWorksheet metadataSheet
133+
134+
run.Tables
135+
|> Seq.iteri (fun i -> ArcTable.toFsWorksheet (Some i) >> doc.AddWorksheet)
136+
137+
138+
doc
139+
140+
/// Write a run to a spreadsheet
141+
member this.ToFsWorkbook () =
142+
ArcRun.toFsWorkbook (this)

0 commit comments

Comments
 (0)