openworm / tracker-commons

Compilation of information and code bases related to open-source trackers for C. elegans
11 stars 12 forks source link

Creating WCON-structured data in memory is fiddly #135

Open Ichoran opened 7 years ago

Ichoran commented 7 years ago

I propose that every language that we support provide a basic set of routines to help the user create WCON data. These routines would include:

I am not sure to what extent these things already exist, but for the library to be useful we need to be able to create and write data, not just read it.

cheelee commented 7 years ago

I don't think the current WCON interface has an abstract interface to in-memory movement data. I think that would be useful to have, with language-specific implementations.

I believe for now we have an I/O interface in that we get some language specific data structure, from which users are expected to manipulate using language features (e.g. arrays etc ...) .

Ichoran commented 7 years ago

I have a draft in Scala up at https://github.com/Ichoran/tracker-commons/tree/scala-simplified

The Readme gives an example of usage: https://github.com/Ichoran/tracker-commons/tree/scala-simplified/src/scala

The main source file is at https://github.com/Ichoran/tracker-commons/blob/scala-simplified/src/scala/src/main/scala/Create.scala

The basic idea is as follows, in Scala. You create the pieces you need by saying Create.nameOfPiece and then call a chain of methods to add stuff until you have everything you need. This is done in order to let the type system help ensure that the construction is done properly. In other languages with weaker type systems, this can just be a standard mutable builder (i.e. you call the methods repeatedly on the object without chaining them); on languages with liquid or path-dependent types (possibly Kotlin?) or typed reassignment (Rust), you could reassign the variable and preserve the type change.

Languages without type-level guarantees should probably provide a validate method to check everything and/or a conditional creation method that returns some sort of optional construct that is empty if the conditions were not met.

Here's a complete minimal example from my command-line during testing:

scala> Create.wcon().
setMeta(Create.meta().addWho("Rex")).
addData(Create.worm("wiggy").add(0.5, Array(1, 2.5), Array(2, 0.5)).result).
setUnits().result
res1: org.openworm.trackercommons.DataSet = DataSet(Metadata(Vector(),Vector(Rex),None,None,None,None,None,None,None,None,None,None,Vector(),Vector(),None,{}),UnitMap(Map(t -> LinearConvert(s,1.0,0,1,0), y -> LinearConvert(mm,1.0,1,0,0), x -> LinearConvert(mm,1.0,1,0,0)),{}),[Lorg.openworm.trackercommons.Data;@40444407,FileSet(Vector(),0,{}),{})

scala> res1.json
res2: kse.jsonal.Json = { "units":{ "t":"s", "y":"mm", "x":"mm" }, "data":[{ "id":"wiggy", "t":0.5, "x":[1, 2.5], "y":[2, 0.5] }], "metadata":{"who":"Rex"} }