From 00d8fcf95b5aec58cb9903f2b5155ee18721a9a0 Mon Sep 17 00:00:00 2001
From: bruno-f-cruz <7049351+bruno-f-cruz@users.noreply.github.com>
Date: Tue, 3 Dec 2024 02:56:07 -0800
Subject: [PATCH] Add first example
---
.../src/bonsai/Extensions/Experiment.cs | 353 ++++++++++++++++++
.../src/json/experiment-example.json | 14 +
.../src/json/experiment-schema.json | 58 +++
.../src/python/first_model.py | 47 +++
4 files changed, 472 insertions(+)
create mode 100644 _topics/_08_reproducible_research_practices/src/bonsai/Extensions/Experiment.cs
create mode 100644 _topics/_08_reproducible_research_practices/src/json/experiment-example.json
create mode 100644 _topics/_08_reproducible_research_practices/src/json/experiment-schema.json
create mode 100644 _topics/_08_reproducible_research_practices/src/python/first_model.py
diff --git a/_topics/_08_reproducible_research_practices/src/bonsai/Extensions/Experiment.cs b/_topics/_08_reproducible_research_practices/src/bonsai/Extensions/Experiment.cs
new file mode 100644
index 0000000..b46a582
--- /dev/null
+++ b/_topics/_08_reproducible_research_practices/src/bonsai/Extensions/Experiment.cs
@@ -0,0 +1,353 @@
+//----------------------
+//
+// Generated using the NJsonSchema v10.9.0.0 (Newtonsoft.Json v13.0.0.0) (http://NJsonSchema.org)
+//
+//----------------------
+
+
+namespace Experiment
+{
+ #pragma warning disable // Disable all warnings
+
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("Bonsai.Sgen", "0.4.0.0 (Newtonsoft.Json v13.0.0.0, YamlDotNet v13.0.0.0)")]
+ [Bonsai.CombinatorAttribute()]
+ [Bonsai.WorkflowElementCategoryAttribute(Bonsai.ElementCategory.Source)]
+ public partial class Trial
+ {
+
+ private double _interTrialInterval = 1D;
+
+ private int _rewardAmount = 1;
+
+ public Trial()
+ {
+ }
+
+ protected Trial(Trial other)
+ {
+ _interTrialInterval = other._interTrialInterval;
+ _rewardAmount = other._rewardAmount;
+ }
+
+ ///
+ /// Interval between trials in seconds
+ ///
+ [Newtonsoft.Json.JsonPropertyAttribute("inter_trial_interval")]
+ [YamlDotNet.Serialization.YamlMemberAttribute(Alias="inter_trial_interval")]
+ [System.ComponentModel.DescriptionAttribute("Interval between trials in seconds")]
+ public double InterTrialInterval
+ {
+ get
+ {
+ return _interTrialInterval;
+ }
+ set
+ {
+ _interTrialInterval = value;
+ }
+ }
+
+ ///
+ /// Amount of reward given to the animal
+ ///
+ [Newtonsoft.Json.JsonPropertyAttribute("reward_amount")]
+ [YamlDotNet.Serialization.YamlMemberAttribute(Alias="reward_amount")]
+ [System.ComponentModel.DescriptionAttribute("Amount of reward given to the animal")]
+ public int RewardAmount
+ {
+ get
+ {
+ return _rewardAmount;
+ }
+ set
+ {
+ _rewardAmount = value;
+ }
+ }
+
+ public System.IObservable Process()
+ {
+ return System.Reactive.Linq.Observable.Defer(() => System.Reactive.Linq.Observable.Return(new Trial(this)));
+ }
+
+ public System.IObservable Process(System.IObservable source)
+ {
+ return System.Reactive.Linq.Observable.Select(source, _ => new Trial(this));
+ }
+
+ protected virtual bool PrintMembers(System.Text.StringBuilder stringBuilder)
+ {
+ stringBuilder.Append("inter_trial_interval = " + _interTrialInterval + ", ");
+ stringBuilder.Append("reward_amount = " + _rewardAmount);
+ return true;
+ }
+
+ public override string ToString()
+ {
+ System.Text.StringBuilder stringBuilder = new System.Text.StringBuilder();
+ stringBuilder.Append(GetType().Name);
+ stringBuilder.Append(" { ");
+ if (PrintMembers(stringBuilder))
+ {
+ stringBuilder.Append(" ");
+ }
+ stringBuilder.Append("}");
+ return stringBuilder.ToString();
+ }
+ }
+
+
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("Bonsai.Sgen", "0.4.0.0 (Newtonsoft.Json v13.0.0.0, YamlDotNet v13.0.0.0)")]
+ [Bonsai.CombinatorAttribute()]
+ [Bonsai.WorkflowElementCategoryAttribute(Bonsai.ElementCategory.Source)]
+ public partial class Experiment
+ {
+
+ private string _animalId;
+
+ private System.Collections.Generic.List _trials = new System.Collections.Generic.List();
+
+ private int? _rngSeed;
+
+ public Experiment()
+ {
+ }
+
+ protected Experiment(Experiment other)
+ {
+ _animalId = other._animalId;
+ _trials = other._trials;
+ _rngSeed = other._rngSeed;
+ }
+
+ ///
+ /// ID of the animal
+ ///
+ [Newtonsoft.Json.JsonPropertyAttribute("animal_id", Required=Newtonsoft.Json.Required.Always)]
+ [YamlDotNet.Serialization.YamlMemberAttribute(Alias="animal_id")]
+ [System.ComponentModel.DescriptionAttribute("ID of the animal")]
+ public string AnimalId
+ {
+ get
+ {
+ return _animalId;
+ }
+ set
+ {
+ _animalId = value;
+ }
+ }
+
+ ///
+ /// List of trials in the experiment
+ ///
+ [System.Xml.Serialization.XmlIgnoreAttribute()]
+ [Newtonsoft.Json.JsonPropertyAttribute("trials", Required=Newtonsoft.Json.Required.Always)]
+ [YamlDotNet.Serialization.YamlMemberAttribute(Alias="trials")]
+ [System.ComponentModel.DescriptionAttribute("List of trials in the experiment")]
+ public System.Collections.Generic.List Trials
+ {
+ get
+ {
+ return _trials;
+ }
+ set
+ {
+ _trials = value;
+ }
+ }
+
+ ///
+ /// Seed for the random number generator
+ ///
+ [System.Xml.Serialization.XmlIgnoreAttribute()]
+ [Newtonsoft.Json.JsonPropertyAttribute("rng_seed")]
+ [YamlDotNet.Serialization.YamlMemberAttribute(Alias="rng_seed")]
+ [System.ComponentModel.DescriptionAttribute("Seed for the random number generator")]
+ public int? RngSeed
+ {
+ get
+ {
+ return _rngSeed;
+ }
+ set
+ {
+ _rngSeed = value;
+ }
+ }
+
+ public System.IObservable Process()
+ {
+ return System.Reactive.Linq.Observable.Defer(() => System.Reactive.Linq.Observable.Return(new Experiment(this)));
+ }
+
+ public System.IObservable Process(System.IObservable source)
+ {
+ return System.Reactive.Linq.Observable.Select(source, _ => new Experiment(this));
+ }
+
+ protected virtual bool PrintMembers(System.Text.StringBuilder stringBuilder)
+ {
+ stringBuilder.Append("animal_id = " + _animalId + ", ");
+ stringBuilder.Append("trials = " + _trials + ", ");
+ stringBuilder.Append("rng_seed = " + _rngSeed);
+ return true;
+ }
+
+ public override string ToString()
+ {
+ System.Text.StringBuilder stringBuilder = new System.Text.StringBuilder();
+ stringBuilder.Append(GetType().Name);
+ stringBuilder.Append(" { ");
+ if (PrintMembers(stringBuilder))
+ {
+ stringBuilder.Append(" ");
+ }
+ stringBuilder.Append("}");
+ return stringBuilder.ToString();
+ }
+ }
+
+
+ ///
+ /// Serializes a sequence of data model objects into JSON strings.
+ ///
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("Bonsai.Sgen", "0.4.0.0 (Newtonsoft.Json v13.0.0.0, YamlDotNet v13.0.0.0)")]
+ [System.ComponentModel.DescriptionAttribute("Serializes a sequence of data model objects into JSON strings.")]
+ [Bonsai.CombinatorAttribute()]
+ [Bonsai.WorkflowElementCategoryAttribute(Bonsai.ElementCategory.Transform)]
+ public partial class SerializeToJson
+ {
+
+ private System.IObservable Process(System.IObservable source)
+ {
+ return System.Reactive.Linq.Observable.Select(source, value => Newtonsoft.Json.JsonConvert.SerializeObject(value));
+ }
+
+ public System.IObservable Process(System.IObservable source)
+ {
+ return Process(source);
+ }
+
+ public System.IObservable Process(System.IObservable source)
+ {
+ return Process(source);
+ }
+ }
+
+
+ ///
+ /// Deserializes a sequence of JSON strings into data model objects.
+ ///
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("Bonsai.Sgen", "0.4.0.0 (Newtonsoft.Json v13.0.0.0, YamlDotNet v13.0.0.0)")]
+ [System.ComponentModel.DescriptionAttribute("Deserializes a sequence of JSON strings into data model objects.")]
+ [System.ComponentModel.DefaultPropertyAttribute("Type")]
+ [Bonsai.WorkflowElementCategoryAttribute(Bonsai.ElementCategory.Transform)]
+ [System.Xml.Serialization.XmlIncludeAttribute(typeof(Bonsai.Expressions.TypeMapping))]
+ [System.Xml.Serialization.XmlIncludeAttribute(typeof(Bonsai.Expressions.TypeMapping))]
+ public partial class DeserializeFromJson : Bonsai.Expressions.SingleArgumentExpressionBuilder
+ {
+
+ public DeserializeFromJson()
+ {
+ Type = new Bonsai.Expressions.TypeMapping();
+ }
+
+ public Bonsai.Expressions.TypeMapping Type { get; set; }
+
+ public override System.Linq.Expressions.Expression Build(System.Collections.Generic.IEnumerable arguments)
+ {
+ var typeMapping = (Bonsai.Expressions.TypeMapping)Type;
+ var returnType = typeMapping.GetType().GetGenericArguments()[0];
+ return System.Linq.Expressions.Expression.Call(
+ typeof(DeserializeFromJson),
+ "Process",
+ new System.Type[] { returnType },
+ System.Linq.Enumerable.Single(arguments));
+ }
+
+ private static System.IObservable Process(System.IObservable source)
+ {
+ return System.Reactive.Linq.Observable.Select(source, value => Newtonsoft.Json.JsonConvert.DeserializeObject(value));
+ }
+ }
+
+
+ ///
+ /// Serializes a sequence of data model objects into YAML strings.
+ ///
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("Bonsai.Sgen", "0.4.0.0 (Newtonsoft.Json v13.0.0.0, YamlDotNet v13.0.0.0)")]
+ [System.ComponentModel.DescriptionAttribute("Serializes a sequence of data model objects into YAML strings.")]
+ [Bonsai.CombinatorAttribute()]
+ [Bonsai.WorkflowElementCategoryAttribute(Bonsai.ElementCategory.Transform)]
+ public partial class SerializeToYaml
+ {
+
+ private System.IObservable Process(System.IObservable source)
+ {
+ return System.Reactive.Linq.Observable.Defer(() =>
+ {
+ var serializer = new YamlDotNet.Serialization.SerializerBuilder()
+ .Build();
+ return System.Reactive.Linq.Observable.Select(source, value => serializer.Serialize(value));
+ });
+ }
+
+ public System.IObservable Process(System.IObservable source)
+ {
+ return Process(source);
+ }
+
+ public System.IObservable Process(System.IObservable source)
+ {
+ return Process(source);
+ }
+ }
+
+
+ ///
+ /// Deserializes a sequence of YAML strings into data model objects.
+ ///
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("Bonsai.Sgen", "0.4.0.0 (Newtonsoft.Json v13.0.0.0, YamlDotNet v13.0.0.0)")]
+ [System.ComponentModel.DescriptionAttribute("Deserializes a sequence of YAML strings into data model objects.")]
+ [System.ComponentModel.DefaultPropertyAttribute("Type")]
+ [Bonsai.WorkflowElementCategoryAttribute(Bonsai.ElementCategory.Transform)]
+ [System.Xml.Serialization.XmlIncludeAttribute(typeof(Bonsai.Expressions.TypeMapping))]
+ [System.Xml.Serialization.XmlIncludeAttribute(typeof(Bonsai.Expressions.TypeMapping))]
+ public partial class DeserializeFromYaml : Bonsai.Expressions.SingleArgumentExpressionBuilder
+ {
+
+ public DeserializeFromYaml()
+ {
+ Type = new Bonsai.Expressions.TypeMapping();
+ }
+
+ public Bonsai.Expressions.TypeMapping Type { get; set; }
+
+ public override System.Linq.Expressions.Expression Build(System.Collections.Generic.IEnumerable arguments)
+ {
+ var typeMapping = (Bonsai.Expressions.TypeMapping)Type;
+ var returnType = typeMapping.GetType().GetGenericArguments()[0];
+ return System.Linq.Expressions.Expression.Call(
+ typeof(DeserializeFromYaml),
+ "Process",
+ new System.Type[] { returnType },
+ System.Linq.Enumerable.Single(arguments));
+ }
+
+ private static System.IObservable Process(System.IObservable source)
+ {
+ return System.Reactive.Linq.Observable.Defer(() =>
+ {
+ var serializer = new YamlDotNet.Serialization.DeserializerBuilder()
+ .Build();
+ return System.Reactive.Linq.Observable.Select(source, value =>
+ {
+ var reader = new System.IO.StringReader(value);
+ var parser = new YamlDotNet.Core.MergingParser(new YamlDotNet.Core.Parser(reader));
+ return serializer.Deserialize(parser);
+ });
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/_topics/_08_reproducible_research_practices/src/json/experiment-example.json b/_topics/_08_reproducible_research_practices/src/json/experiment-example.json
new file mode 100644
index 0000000..c12af00
--- /dev/null
+++ b/_topics/_08_reproducible_research_practices/src/json/experiment-example.json
@@ -0,0 +1,14 @@
+{
+ "animal_id": "my_mouse",
+ "trials": [
+ {
+ "inter_trial_interval": 1.0,
+ "reward_amount": 1
+ },
+ {
+ "inter_trial_interval": 0.5,
+ "reward_amount": 0
+ }
+ ],
+ "rng_seed": null
+}
\ No newline at end of file
diff --git a/_topics/_08_reproducible_research_practices/src/json/experiment-schema.json b/_topics/_08_reproducible_research_practices/src/json/experiment-schema.json
new file mode 100644
index 0000000..2c680af
--- /dev/null
+++ b/_topics/_08_reproducible_research_practices/src/json/experiment-schema.json
@@ -0,0 +1,58 @@
+{
+ "definitions": {
+ "Trial": {
+ "properties": {
+ "inter_trial_interval": {
+ "default": 1.0,
+ "description": "Interval between trials in seconds",
+ "minimum": 0.0,
+ "title": "Inter Trial Interval",
+ "type": "number"
+ },
+ "reward_amount": {
+ "default": 1,
+ "description": "Amount of reward given to the animal",
+ "minimum": 0,
+ "title": "Reward Amount",
+ "type": "integer"
+ }
+ },
+ "title": "Trial",
+ "type": "object"
+ }
+ },
+ "properties": {
+ "animal_id": {
+ "description": "ID of the animal",
+ "title": "Animal Id",
+ "type": "string"
+ },
+ "trials": {
+ "description": "List of trials in the experiment",
+ "items": {
+ "$ref": "#/definitions/Trial"
+ },
+ "title": "Trials",
+ "type": "array"
+ },
+ "rng_seed": {
+ "default": null,
+ "description": "Seed for the random number generator",
+ "oneOf": [
+ {
+ "type": "integer"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "title": "Rng Seed"
+ }
+ },
+ "required": [
+ "animal_id",
+ "trials"
+ ],
+ "title": "Experiment",
+ "type": "object"
+}
\ No newline at end of file
diff --git a/_topics/_08_reproducible_research_practices/src/python/first_model.py b/_topics/_08_reproducible_research_practices/src/python/first_model.py
new file mode 100644
index 0000000..f84178b
--- /dev/null
+++ b/_topics/_08_reproducible_research_practices/src/python/first_model.py
@@ -0,0 +1,47 @@
+from pydantic import BaseModel, Field
+from typing import List, Optional
+from _utils import export_schema, bonsai_sgen, BonsaiSgenSerializers
+from pathlib import Path
+
+
+class Trial(BaseModel):
+ inter_trial_interval: float = Field(
+ default=1.0, ge=0, description="Interval between trials in seconds"
+ )
+ reward_amount: int = Field(
+ default=1, ge=0, description="Amount of reward given to the animal"
+ )
+
+
+class Experiment(BaseModel):
+ animal_id: str = Field(description="ID of the animal")
+ trials: List[Trial] = Field(description="List of trials in the experiment")
+ rng_seed: Optional[int] = Field(
+ default=None, description="Seed for the random number generator"
+ )
+
+
+if __name__ == "__main__":
+ json_schema = export_schema(Experiment)
+ name = (Experiment.__name__).lower()
+ schema_path = Path(rf"src/json/{name}-schema.json")
+ with open(schema_path, "w", encoding="utf-8") as f:
+ f.write(json_schema)
+
+ bonsai_sgen(
+ schema_path=schema_path,
+ output_path=Path(rf"src/bonsai/Extensions/{name.capitalize()}.cs"),
+ namespace=name.capitalize(),
+ serializer=[BonsaiSgenSerializers.JSON, BonsaiSgenSerializers.YAML],
+ )
+
+ experiment_example = Experiment(
+ animal_id="my_mouse",
+ trials=[
+ Trial(inter_trial_interval=1.0, reward_amount=1),
+ Trial(inter_trial_interval=0.5, reward_amount=0),
+ ],
+ )
+
+ with open(rf"src/json/{name}-example.json", "w", encoding="utf-8") as f:
+ f.write(experiment_example.model_dump_json(indent=2))