mirror of
https://github.com/psychopy/psychojs.git
synced 2025-05-10 10:40:54 +00:00
FF completed the information available in the experiment data for MultiStairHandler
This commit is contained in:
parent
3424b24b43
commit
86dee66770
@ -143,7 +143,7 @@ export class ServerManager extends PsychObject
|
||||
{
|
||||
const url = this._psychoJS.config.pavlovia.URL
|
||||
+ "/api/v2/experiments/" + this._psychoJS.config.gitlab.projectId
|
||||
+ "/sessions/";
|
||||
+ "/sessions";
|
||||
jQuery.post(url, data, null, "json")
|
||||
.done((data, textStatus) =>
|
||||
{
|
||||
@ -324,30 +324,72 @@ export class ServerManager extends PsychObject
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Get the status of a resource.
|
||||
* Get the status of a single resource or the reduced status of an array of resources.
|
||||
*
|
||||
* <p>If an array of resources is given, getResourceStatus returns a single, reduced status
|
||||
* that is the status furthest away from DOWNLOADED, with the status ordered as follow:
|
||||
* ERROR (furthest from DOWNLOADED), REGISTERED, DOWNLOADING, and DOWNLOADED</p>
|
||||
* <p>For example, given three resources:
|
||||
* <ul>
|
||||
* <li>if at least one of the resource status is ERROR, the reduced status is ERROR</li>
|
||||
* <li>if at least one of the resource status is DOWNLOADING, the reduced status is DOWNLOADING</li>
|
||||
* <li>if the status of all three resources is REGISTERED, the reduced status is REGISTERED</li>
|
||||
* <li>if the status of all three resources is DOWNLOADED, the reduced status is DOWNLOADED</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*
|
||||
* @name module:core.ServerManager#getResourceStatus
|
||||
* @function
|
||||
* @public
|
||||
* @param {string} name of the requested resource
|
||||
* @return {core.ServerManager.ResourceStatus} status of the resource
|
||||
* @throws {Object.<string, *>} exception if no resource with that name has previously been registered
|
||||
* @param {string | string[]} names names of the resources whose statuses are requested
|
||||
* @return {core.ServerManager.ResourceStatus} status of the resource if there is only one, or reduced status otherwise
|
||||
* @throws {Object.<string, *>} if at least one of the names is not that of a previously
|
||||
* registered resource
|
||||
*/
|
||||
getResourceStatus(name)
|
||||
getResourceStatus(names)
|
||||
{
|
||||
const response = {
|
||||
origin: "ServerManager.getResourceStatus",
|
||||
context: "when getting the status of resource: " + name,
|
||||
context: `when getting the status of resource(s): ${JSON.stringify(names)}`,
|
||||
};
|
||||
|
||||
const pathStatusData = this._resources.get(name);
|
||||
if (typeof pathStatusData === "undefined")
|
||||
// sanity checks:
|
||||
if (typeof names === 'string')
|
||||
{
|
||||
// throw { ...response, error: 'unknown resource' };
|
||||
throw Object.assign(response, { error: "unknown resource" });
|
||||
names = [names];
|
||||
}
|
||||
if (!Array.isArray(names))
|
||||
{
|
||||
throw Object.assign(response, { error: "names should be either a string or an array of strings" });
|
||||
}
|
||||
const statusOrder = new Map([
|
||||
[Symbol.keyFor(ServerManager.ResourceStatus.ERROR), 0],
|
||||
[Symbol.keyFor(ServerManager.ResourceStatus.REGISTERED), 1],
|
||||
[Symbol.keyFor(ServerManager.ResourceStatus.DOWNLOADING), 2],
|
||||
[Symbol.keyFor(ServerManager.ResourceStatus.DOWNLOADED), 3]
|
||||
]);
|
||||
let reducedStatus = ServerManager.ResourceStatus.DOWNLOADED;
|
||||
for (const name of names)
|
||||
{
|
||||
const pathStatusData = this._resources.get(name);
|
||||
|
||||
if (typeof pathStatusData === "undefined")
|
||||
{
|
||||
// throw { ...response, error: 'unknown resource' };
|
||||
throw Object.assign(response, {
|
||||
error: `unable to find a previously registered resource with name: ${name}`
|
||||
});
|
||||
}
|
||||
|
||||
// update the reduced status according to the order given by statusOrder:
|
||||
if (statusOrder.get(Symbol.keyFor(pathStatusData.status)) <
|
||||
statusOrder.get(Symbol.keyFor(reducedStatus)))
|
||||
{
|
||||
reducedStatus = pathStatusData.status;
|
||||
}
|
||||
}
|
||||
|
||||
return pathStatusData.status;
|
||||
return reducedStatus;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -410,7 +452,7 @@ export class ServerManager extends PsychObject
|
||||
* </ul>
|
||||
*
|
||||
* @name module:core.ServerManager#prepareResources
|
||||
* @param {Array.<{name: string, path: string, download: boolean} | String | Symbol>} [resources=[]] - the list of resources
|
||||
* @param {String | Array.<{name: string, path: string, download: boolean} | String | Symbol>} [resources=[]] - the list of resources or a single resource
|
||||
* @function
|
||||
* @public
|
||||
*/
|
||||
@ -430,9 +472,13 @@ export class ServerManager extends PsychObject
|
||||
// register the resources:
|
||||
if (resources !== null)
|
||||
{
|
||||
if (typeof resources === "string")
|
||||
{
|
||||
resources = [resources];
|
||||
}
|
||||
if (!Array.isArray(resources))
|
||||
{
|
||||
throw "resources should be an array of string or objects";
|
||||
throw "resources should be either (a) a string or (b) an array of string or objects";
|
||||
}
|
||||
|
||||
// whether all resources have been requested:
|
||||
@ -524,19 +570,26 @@ export class ServerManager extends PsychObject
|
||||
|
||||
// download those registered resources for which download = true
|
||||
// note: we return a Promise that will be resolved when all the resources are downloaded
|
||||
return new Promise((resolve, reject) =>
|
||||
if (resourcesToDownload.size === 0)
|
||||
{
|
||||
const uuid = this.on(ServerManager.Event.RESOURCE, (signal) =>
|
||||
return Promise.resolve();
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Promise((resolve, reject) =>
|
||||
{
|
||||
if (signal.message === ServerManager.Event.DOWNLOAD_COMPLETED)
|
||||
const uuid = this.on(ServerManager.Event.RESOURCE, (signal) =>
|
||||
{
|
||||
this.off(ServerManager.Event.RESOURCE, uuid);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
if (signal.message === ServerManager.Event.DOWNLOAD_COMPLETED)
|
||||
{
|
||||
this.off(ServerManager.Event.RESOURCE, uuid);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
|
||||
this._downloadResources(resourcesToDownload);
|
||||
});
|
||||
this._downloadResources(resourcesToDownload);
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
@ -1357,6 +1410,11 @@ ServerManager.Status = {
|
||||
* @public
|
||||
*/
|
||||
ServerManager.ResourceStatus = {
|
||||
/**
|
||||
* There was an error during downloading, or the resource is in an unknown state.
|
||||
*/
|
||||
ERROR: Symbol.for("ERROR"),
|
||||
|
||||
/**
|
||||
* The resource has been registered.
|
||||
*/
|
||||
@ -1371,9 +1429,4 @@ ServerManager.ResourceStatus = {
|
||||
* The resource has been downloaded.
|
||||
*/
|
||||
DOWNLOADED: Symbol.for("DOWNLOADED"),
|
||||
|
||||
/**
|
||||
* There was an error during downloading, or the resource is in an unknown state.
|
||||
*/
|
||||
ERROR: Symbol.for("ERROR"),
|
||||
};
|
||||
|
@ -115,6 +115,7 @@ export class ExperimentHandler extends PsychObject
|
||||
* @function
|
||||
* @public
|
||||
* @returns {boolean} whether or not the current entry is empty
|
||||
* @todo This really should be renamed: IsCurrentEntryNotEmpty
|
||||
*/
|
||||
isEntryEmpty()
|
||||
{
|
||||
|
@ -111,10 +111,12 @@ export class MultiStairHandler extends TrialHandler
|
||||
};
|
||||
}
|
||||
|
||||
this._psychoJS.experiment.addData(this._name+'.response', response);
|
||||
|
||||
if (!this._finished)
|
||||
{
|
||||
// update the current staircase:
|
||||
this._currentStaircase.addResponse(response, value);
|
||||
// update the current staircase, but do not add the response again:
|
||||
this._currentStaircase.addResponse(response, value, false);
|
||||
|
||||
// move onto the next trial:
|
||||
this._nextTrial();
|
||||
@ -206,6 +208,7 @@ export class MultiStairHandler extends TrialHandler
|
||||
const args = Object.assign({}, condition);
|
||||
args.psychoJS = this._psychoJS;
|
||||
args.varName = this._varName;
|
||||
// label becomes name:
|
||||
args.name = condition.label;
|
||||
args.autoLog = this._autoLog;
|
||||
if (typeof condition.nTrials === "undefined")
|
||||
@ -254,7 +257,7 @@ export class MultiStairHandler extends TrialHandler
|
||||
// if the current pass is empty, get a new one:
|
||||
if (this._currentPass.length === 0)
|
||||
{
|
||||
this._currentPass = this._staircases.filter(handler => !handler.finished);
|
||||
this._currentPass = this._staircases.filter( handler => !handler.finished );
|
||||
|
||||
if (this._multiMethod === TrialHandler.Method.SEQUENTIAL)
|
||||
{
|
||||
@ -322,12 +325,48 @@ export class MultiStairHandler extends TrialHandler
|
||||
{
|
||||
if (typeof this._trialList[t] === "undefined")
|
||||
{
|
||||
this._trialList[t] = {[this._varName]: value};
|
||||
this._trialList[t] = {
|
||||
[this._name+"."+this._varName]: value,
|
||||
[this._name+".intensity"]: value
|
||||
};
|
||||
for (const attribute of this._currentStaircase._userAttributes)
|
||||
{
|
||||
// "name" becomes "label" again:
|
||||
if (attribute === "name")
|
||||
{
|
||||
this._trialList[t][this._name+".label"] = this._currentStaircase["_name"];
|
||||
}
|
||||
else if (attribute !== "trialList" && attribute !== "extraInfo")
|
||||
{
|
||||
this._trialList[t][this._name+"."+attribute] = this._currentStaircase["_" + attribute];
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof this._snapshots[t] !== "undefined")
|
||||
{
|
||||
this._snapshots[t][this._varName] = value;
|
||||
this._snapshots[t].trialAttributes.push(this._varName);
|
||||
let fieldName = this._name + "." + this._varName;
|
||||
this._snapshots[t][fieldName] = value;
|
||||
this._snapshots[t].trialAttributes.push(fieldName);
|
||||
fieldName = this._name + ".intensity";
|
||||
this._snapshots[t][fieldName] = value;
|
||||
this._snapshots[t].trialAttributes.push(fieldName);
|
||||
|
||||
for (const attribute of this._currentStaircase._userAttributes)
|
||||
{
|
||||
// "name" becomes "label" again:
|
||||
if (attribute === 'name')
|
||||
{
|
||||
fieldName = this._name + ".label";
|
||||
this._snapshots[t][fieldName] = this._currentStaircase["_name"];
|
||||
this._snapshots[t].trialAttributes.push(fieldName);
|
||||
}
|
||||
else if (attribute !== 'trialList' && attribute !== 'extraInfo')
|
||||
{
|
||||
fieldName = this._name+"."+attribute;
|
||||
this._snapshots[t][fieldName] = this._currentStaircase["_" + attribute];
|
||||
this._snapshots[t].trialAttributes.push(fieldName);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -118,10 +118,12 @@ export class QuestHandler extends TrialHandler
|
||||
* @public
|
||||
* @param{number} response - the response to the trial, must be either 0 (incorrect or
|
||||
* non-detected) or 1 (correct or detected)
|
||||
* @param{number | undefined} [value] - optional intensity / contrast / threshold
|
||||
* @param{number | undefined} value - optional intensity / contrast / threshold
|
||||
* @param{boolean} [doAddData = true] - whether or not to add the response as data to the
|
||||
* experiment
|
||||
* @returns {void}
|
||||
*/
|
||||
addResponse(response, value)
|
||||
addResponse(response, value, doAddData = true)
|
||||
{
|
||||
// check that response is either 0 or 1:
|
||||
if (response !== 0 && response !== 1)
|
||||
@ -133,6 +135,11 @@ export class QuestHandler extends TrialHandler
|
||||
};
|
||||
}
|
||||
|
||||
if (doAddData)
|
||||
{
|
||||
this._psychoJS.experiment.addData(this._name + '.response', response);
|
||||
}
|
||||
|
||||
// update the QUEST pdf:
|
||||
if (typeof value !== "undefined")
|
||||
{
|
||||
@ -145,7 +152,10 @@ export class QuestHandler extends TrialHandler
|
||||
|
||||
if (!this._finished)
|
||||
{
|
||||
// estimate the next value of the QUEST variable (and update the trial list and snapshots):
|
||||
this.next();
|
||||
|
||||
// estimate the next value of the QUEST variable
|
||||
// (and update the trial list and snapshots):
|
||||
this._estimateQuestValue();
|
||||
}
|
||||
}
|
||||
|
@ -688,7 +688,7 @@ export class TrialHandler extends PsychObject
|
||||
context: "when preparing a sequence of trials",
|
||||
};
|
||||
|
||||
// get an array of the indices of the elements of trialList :
|
||||
// get an array of the indices of the elements of trialList:
|
||||
const indices = Array.from(this.trialList.keys());
|
||||
|
||||
if (this._method === TrialHandler.Method.SEQUENTIAL)
|
||||
|
Loading…
Reference in New Issue
Block a user