Skip to content

Commit a3cb145

Browse files
committed
add saveData setting
1 parent 9de251d commit a3cb145

12 files changed

+256
-37
lines changed

Assets/UXF/Scripts/Etc/Block.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace UXF
88
/// <summary>
99
/// A set of trials, often used to group a number of consecutive Trial objects that share something in common.
1010
/// </summary>
11-
public class Block : ISettingsContainer
11+
public class Block : IExperimentUnit
1212
{
1313
/// <summary>
1414
/// List of trials associated with this block
@@ -33,13 +33,21 @@ public class Block : ISettingsContainer
3333
/// <summary>
3434
/// Block settings. These will be overridden by trial settings if set.
3535
/// </summary>
36-
public Settings settings { get; private set; }
36+
public Settings settings { get; protected set; }
3737

3838
/// <summary>
3939
/// The session associated with this block
4040
/// </summary>
4141
public Session session { get; private set; }
4242

43+
/// <summary>
44+
/// Should data be saved for this session?
45+
/// </summary>
46+
public bool saveData
47+
{
48+
get => settings.GetBool(Constants.SAVE_DATA_SETTING_NAME, true);
49+
set => settings.SetValue(Constants.SAVE_DATA_SETTING_NAME, value);
50+
}
4351

4452
/// <summary>
4553
/// Create a block with a given number of trials under a given session

Assets/UXF/Scripts/Etc/Constants.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using UnityEngine;
2+
3+
namespace UXF
4+
{
5+
public static class Constants
6+
{
7+
public const string SAVE_DATA_SETTING_NAME = "_UXFInternal_SaveData";
8+
}
9+
}

Assets/UXF/Scripts/Etc/Constants.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using System;
2+
using System.Linq;
3+
using System.Collections;
4+
using System.Collections.Generic;
5+
using UnityEngine;
6+
7+
namespace UXF
8+
{
9+
/// <summary>
10+
/// Represents a unit of an experiment.
11+
/// </summary>
12+
public interface IExperimentUnit : ISettingsContainer
13+
{
14+
/// <summary>
15+
/// Sets wether data should be saved for this experiment unit.
16+
/// </summary>
17+
bool saveData { get; }
18+
}
19+
}

Assets/UXF/Scripts/Etc/IExperimentUnit.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Assets/UXF/Scripts/Etc/Trial.cs

Lines changed: 44 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ namespace UXF
1313
/// The base unit of experiments. A Trial is usually a singular attempt at a task by a participant after/during the presentation of a stimulus.
1414
/// </summary>
1515
[Serializable]
16-
public class Trial : ISettingsContainer, IDataAssociatable
16+
public class Trial : IExperimentUnit, IDataAssociatable
1717
{
1818

1919
/// <summary>
@@ -46,7 +46,16 @@ public class Trial : ISettingsContainer, IDataAssociatable
4646
/// <summary>
4747
/// Trial settings. These will override block settings if set.
4848
/// </summary>
49-
public Settings settings { get; private set; }
49+
public Settings settings { get; protected set; }
50+
51+
/// <summary>
52+
/// Should data be saved for this session?
53+
/// </summary>
54+
public bool saveData
55+
{
56+
get => settings.GetBool(Constants.SAVE_DATA_SETTING_NAME, true);
57+
set => settings.SetValue(Constants.SAVE_DATA_SETTING_NAME, value);
58+
}
5059

5160
/// <summary>
5261
/// Dictionary of results in a order.
@@ -121,34 +130,10 @@ public void End()
121130
status = TrialStatus.Done;
122131
endTime = Time.time;
123132
result["end_time"] = endTime;
124-
125-
// check no duplicate trackers
126-
List<string> duplicateTrackers = session.trackedObjects.Where(tracker => tracker != null)
127-
.GroupBy(tracker => tracker.DataName)
128-
.Where(g => g.Count() > 1)
129-
.Select(y => y.Key)
130-
.ToList();
131-
132-
if (duplicateTrackers.Any()) throw new InvalidOperationException(string.Format("Two or more trackers in the Tracked Objects field in the Session Inspector have the following object name and descriptor pair, please change the object name fields on the trackers to make them unique: {0}", string.Join(",", duplicateTrackers)));
133-
134-
// log tracked objects
135-
foreach (Tracker tracker in session.trackedObjects)
136-
{
137-
try
138-
{
139-
tracker.StopRecording();
140-
SaveDataTable(tracker.Data, tracker.DataName, dataType: UXFDataType.Trackers);
141-
}
142-
catch (NullReferenceException)
143-
{
144-
Utilities.UXFDebugLogWarning("An item in the Tracked Objects field of the UXF session if empty (null)!");
145-
}
146-
}
147-
148-
// log any settings we need to for this trial
149-
foreach (string s in session.settingsToLog)
133+
134+
if (saveData)
150135
{
151-
result[s] = settings.GetObject(s, string.Empty);
136+
SaveData();
152137
}
153138

154139
session.onTrialEnd.Invoke(this);
@@ -262,7 +247,37 @@ public void SaveBytes(byte[] bytes, string dataName, UXFDataType dataType = UXFD
262247
}
263248
}
264249

250+
private void SaveData()
251+
{
252+
// check no duplicate trackers
253+
List<string> duplicateTrackers = session.trackedObjects.Where(tracker => tracker != null)
254+
.GroupBy(tracker => tracker.DataName)
255+
.Where(g => g.Count() > 1)
256+
.Select(y => y.Key)
257+
.ToList();
258+
259+
if (duplicateTrackers.Any()) throw new InvalidOperationException(string.Format("Two or more trackers in the Tracked Objects field in the Session Inspector have the following object name and descriptor pair, please change the object name fields on the trackers to make them unique: {0}", string.Join(",", duplicateTrackers)));
260+
261+
// log tracked objects
262+
foreach (Tracker tracker in session.trackedObjects)
263+
{
264+
try
265+
{
266+
tracker.StopRecording();
267+
SaveDataTable(tracker.Data, tracker.DataName, dataType: UXFDataType.Trackers);
268+
}
269+
catch (NullReferenceException)
270+
{
271+
Utilities.UXFDebugLogWarning("An item in the Tracked Objects field of the UXF session if empty (null)!");
272+
}
273+
}
265274

275+
// log any settings we need to for this trial
276+
foreach (string s in session.settingsToLog)
277+
{
278+
result[s] = settings.GetObject(s, string.Empty);
279+
}
280+
}
266281
}
267282

268283

Assets/UXF/Scripts/Session.cs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ namespace UXF
1414
/// The Session represents a single "run" of an experiment, and contains all information about that run.
1515
/// </summary>
1616
[ExecuteInEditMode]
17-
public class Session : MonoBehaviour, ISettingsContainer, IDataAssociatable
17+
public class Session : MonoBehaviour, IExperimentUnit, IDataAssociatable
1818
{
1919
/// <summary>
2020
/// Enable to automatically safely end the session when the application is quitting.
@@ -252,6 +252,15 @@ public class Session : MonoBehaviour, ISettingsContainer, IDataAssociatable
252252
/// </summary>
253253
public IEnumerable<DataHandler> ActiveDataHandlers { get { return dataHandlers.Where(d => d != null && d.active).Distinct(); }}
254254

255+
/// <summary>
256+
/// Should data be saved for this session?
257+
/// </summary>
258+
public bool saveData
259+
{
260+
get => settings.GetBool(Constants.SAVE_DATA_SETTING_NAME, true);
261+
set => settings.SetValue(Constants.SAVE_DATA_SETTING_NAME, value);
262+
}
263+
255264
/// <summary>
256265
/// Provide references to other components
257266
/// </summary>
@@ -628,13 +637,13 @@ public void End()
628637
try { preSessionEnd.Invoke(this); }
629638
catch (Exception e) { Debug.LogException(e); }
630639

631-
if (storeSessionSettings)
640+
if (storeSessionSettings && saveData)
632641
{
633642
// copy Settings to session folder
634643
SaveJSONSerializableObject(new Dictionary<string, object>(settings.baseDict), "settings", dataType: UXFDataType.Settings);
635644
}
636645

637-
if (storeParticipantDetails)
646+
if (storeParticipantDetails && saveData)
638647
{
639648
// copy participant details to session folder
640649
// we convert to a DataTable because we know the dictionary will be "flat" (one value per key)
@@ -674,14 +683,14 @@ void SaveResults()
674683
// hashset keeps unique set of keys
675684
HashSet<string> resultsHeaders = new HashSet<string>();
676685
foreach (Trial t in Trials)
677-
if (t.result != null)
686+
if (t.result != null && t.saveData)
678687
foreach (string key in t.result.Keys)
679688
resultsHeaders.Add(key);
680689

681690
UXFDataTable table = new UXFDataTable(Trials.Count(), resultsHeaders.ToArray());
682691
foreach (Trial t in Trials)
683692
{
684-
if (t.result != null)
693+
if (t.result != null && t.saveData)
685694
{
686695
UXFDataRow row = new UXFDataRow();
687696
foreach (string h in resultsHeaders)

Assets/UXF/Scripts/SessionLogger.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,10 @@ public void Log(string text, string logType = "user")
8585
/// </summary>
8686
public void Finalise(Session session)
8787
{
88-
session.SaveDataTable(table, "log", dataType: UXFDataType.SessionLog);
88+
if (session.saveData)
89+
{
90+
session.SaveDataTable(table, "log", dataType: UXFDataType.SessionLog);
91+
}
8992

9093
if (logDebugLogCalls) Application.logMessageReceived -= HandleLog;
9194
session.preSessionEnd.RemoveListener(Finalise);
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using UnityEngine;
2+
using UnityEditor;
3+
using UnityEngine.TestTools;
4+
using NUnit.Framework;
5+
using System;
6+
using System.Collections;
7+
using System.Collections.Generic;
8+
using System.IO;
9+
10+
11+
namespace UXF.Tests
12+
{
13+
public class TestSaveTrialData
14+
{
15+
16+
[Test]
17+
public void TestDoNotSaveSomeTrials()
18+
{
19+
(Session session, TestableDataHandler dataHandler) = CreateSession("DoNotSaveSomeTrials");
20+
session.blocks[0].trials[0].saveData = false;
21+
session.blocks[1].saveData = false;
22+
23+
foreach (var t in session.Trials)
24+
{
25+
t.Begin();
26+
t.End();
27+
}
28+
29+
session.End();
30+
31+
var results = dataHandler.trialResults;
32+
33+
Assert.AreEqual(1, results.CountRows());
34+
}
35+
36+
Tuple<Session, TestableDataHandler> CreateSession(string ppidExtra)
37+
{
38+
GameObject gameObject = new GameObject();
39+
TestableDataHandler dataHandler = gameObject.AddComponent<TestableDataHandler>();
40+
SessionLogger sessionLogger = gameObject.AddComponent<SessionLogger>();
41+
if (Session.instance != null) GameObject.DestroyImmediate(Session.instance.gameObject);
42+
Session session = gameObject.AddComponent<Session>();
43+
sessionLogger.AttachReferences(
44+
session
45+
);
46+
47+
session.dataHandlers = new DataHandler[]{ dataHandler };
48+
49+
sessionLogger.Initialise();
50+
51+
string experimentName = "unit_test";
52+
string ppid = "test_behaviour_" + ppidExtra;
53+
session.Begin(experimentName, ppid);
54+
55+
// generate trials
56+
session.CreateBlock(2);
57+
session.CreateBlock(3);
58+
59+
return new Tuple<Session, TestableDataHandler>(session, dataHandler);
60+
}
61+
62+
}
63+
64+
}

Assets/UXF/Tests/Editor/TestSaveTrialData.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using UnityEngine;
2+
using System.Linq;
3+
using System;
4+
using System.Collections;
5+
using System.Collections.Generic;
6+
7+
8+
namespace UXF.Tests
9+
{
10+
public class TestableDataHandler : DataHandler
11+
{
12+
public UXFDataTable trialResults;
13+
14+
public override bool CheckIfRiskOfOverwrite(string experiment, string ppid, int sessionNum, string rootPath = "")
15+
{
16+
return false;
17+
}
18+
19+
public override string HandleBytes(byte[] bytes, string experiment, string ppid, int sessionNum, string dataName, UXFDataType dataType, int optionalTrialNumber = 0)
20+
{
21+
return String.Empty;
22+
}
23+
24+
public override string HandleDataTable(UXFDataTable table, string experiment, string ppid, int sessionNum, string dataName, UXFDataType dataType, int optionalTrialNumber = 0)
25+
{
26+
if (dataType == UXFDataType.TrialResults)
27+
{
28+
trialResults = table;
29+
}
30+
return String.Empty;
31+
}
32+
33+
public override string HandleJSONSerializableObject(List<object> serializableObject, string experiment, string ppid, int sessionNum, string dataName, UXFDataType dataType, int optionalTrialNumber = 0)
34+
{
35+
return String.Empty;
36+
}
37+
38+
public override string HandleJSONSerializableObject(Dictionary<string, object> serializableObject, string experiment, string ppid, int sessionNum, string dataName, UXFDataType dataType, int optionalTrialNumber = 0)
39+
{
40+
return String.Empty;
41+
}
42+
43+
public override string HandleText(string text, string experiment, string ppid, int sessionNum, string dataName, UXFDataType dataType, int optionalTrialNumber = 0)
44+
{
45+
return String.Empty;
46+
}
47+
}
48+
}

0 commit comments

Comments
 (0)