Skip to content

Commit

Permalink
Merge pull request #147 from makebrainwaves/dano/experiment-readd
Browse files Browse the repository at this point in the history
Re-add Stroop, Search, and Multitasking Experiments
  • Loading branch information
jdpigeon authored Dec 16, 2020
2 parents 415aa13 + 8a08194 commit 732a05b
Show file tree
Hide file tree
Showing 27 changed files with 871 additions and 928 deletions.
8 changes: 4 additions & 4 deletions app/components/CollectComponent/PreTestComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import PreviewExperimentComponent from '../PreviewExperimentComponent';
import PreviewButton from '../PreviewButtonComponent';
import { HelpSidebar, HelpButton } from './HelpSidebar';
import styles from '../styles/collect.css';
import { loadProtocol } from '../../utils/labjs/functions';
import { getExperimentFromType } from '../../utils/labjs/functions';
import { ExperimentActions, DeviceActions } from '../../actions';
import {
DEVICES,
Expand All @@ -23,7 +23,7 @@ import {
PLOTTING_INTERVAL,
CONNECTION_STATUS,
} from '../../constants/constants';
import { ExperimentParameters, Trial } from '../../constants/interfaces';
import { ExperimentParameters } from '../../constants/interfaces';

interface Props {
ExperimentActions: typeof ExperimentActions;
Expand Down Expand Up @@ -93,11 +93,11 @@ export default class PreTestComponent extends Component<Props, State> {
if (this.state.isPreviewing) {
return (
<PreviewExperimentComponent
{...loadProtocol(this.props.type)}
{...getExperimentFromType(this.props.type)}
isPreviewing={this.state.isPreviewing}
onEnd={this.endPreview}
type={this.props.type}
previewParams={this.props.params}
params={this.props.params}
title={this.props.title}
/>
);
Expand Down
21 changes: 7 additions & 14 deletions app/components/DesignComponent/CustomDesignComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,19 @@ import {
Table,
CheckboxProps,
} from 'semantic-ui-react';
import { isNil, isString } from 'lodash';
import { History } from 'history';
import { isString } from 'lodash';

import styles from '../styles/common.css';
import { EXPERIMENTS, SCREENS } from '../../constants/constants';
import {
ExperimentObject,
ExperimentParameters,
} from '../../constants/interfaces';
import { SCREENS } from '../../constants/constants';
import { ExperimentParameters } from '../../constants/interfaces';
import { DesignProps } from './index';
import SecondaryNavComponent from '../SecondaryNavComponent';
import PreviewExperimentComponent from '../PreviewExperimentComponent';
import StimuliDesignColumn from './StimuliDesignColumn';
import { ParamSlider } from './ParamSlider';
import PreviewButton from '../PreviewButtonComponent';
import researchQuestionImage from '../../assets/common/ResearchQuestion2.png';
import methodsImage from '../../assets/common/Methods2.png';
import hypothesisImage from '../../assets/common/Hypothesis2.png';
import { readImages } from '../../utils/filesystem/storage';
import { StimuliRow } from './StimuliRow';
import { ExperimentActions } from '../../actions/experimentActions';

const CUSTOM_STEPS = {
OVERVIEW: 'OVERVIEW',
Expand Down Expand Up @@ -112,6 +104,7 @@ export default class CustomDesign extends Component<DesignProps, State> {
}

handleSetText(text: string, section: 'hypothesis' | 'methods' | 'question') {
// @ts-expect-error
this.setState((prevState) => ({
params: {
...prevState.params,
Expand Down Expand Up @@ -152,7 +145,7 @@ export default class CustomDesign extends Component<DesignProps, State> {
autoHeight
style={{ minHeight: 100, maxHeight: 400 }}
label={FIELDS.QUESTION}
value={this.state.params.description.question}
value={this.state.params.description?.question}
placeholder="Explain your research question here."
onChange={(event, data) => {
if (!isString(data.value)) {
Expand All @@ -176,7 +169,7 @@ export default class CustomDesign extends Component<DesignProps, State> {
autoHeight
style={{ minHeight: 100, maxHeight: 400 }}
label={FIELDS.HYPOTHESIS}
value={this.state.params.description.hypothesis}
value={this.state.params.description?.hypothesis}
placeholder="Describe your hypothesis here."
onChange={(event, data) => {
if (!isString(data.value)) {
Expand All @@ -200,7 +193,7 @@ export default class CustomDesign extends Component<DesignProps, State> {
autoHeight
style={{ minHeight: 100, maxHeight: 400 }}
label={FIELDS.METHODS}
value={this.state.params.description.methods}
value={this.state.params.description?.methods}
placeholder="Explain how you will design your experiment to answer the question here."
onChange={(event, data) => {
if (!isString(data.value)) {
Expand Down
15 changes: 12 additions & 3 deletions app/components/ExperimentWindow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as lab from 'lab.js/dist/lab.dev';
import {
ExperimentObject,
ExperimentParameters,
Stimulus,
} from '../constants/interfaces';

export interface ExperimentWindowProps {
Expand Down Expand Up @@ -32,9 +33,17 @@ export const ExperimentWindow: React.FC<ExperimentWindowProps> = ({
const experimentToRun = lab.util.fromObject(experimentClone, lab);

experimentToRun.parameters.title = title;
experimentToRun.options.media.images = params.stimuli.map((stimulus) =>
path.join(stimulus.dir, stimulus.filename)
);
if (params.stimuli) {
experimentToRun.options.media.images = params.stimuli?.reduce<string[]>(
(images, stimulus) => {
if (stimulus.dir && stimulus.filename) {
return [...images, path.join(stimulus.dir, stimulus.filename)];
}
return images;
},
[]
);
}

experimentToRun.on('end', () => {
const csv = experimentToRun.options.datastore.exportCsv();
Expand Down
10 changes: 4 additions & 6 deletions app/components/HomeComponent/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ export default class Home extends Component<Props, State> {
/>
</Grid.Column>

{/* <Grid.Column>
<Grid.Column>
<ExperimentCard
onClick={() => this.handleNewExperiment(EXPERIMENTS.STROOP)}
icon={stroopIcon}
Expand All @@ -313,7 +313,6 @@ export default class Home extends Component<Props, State> {
/>
</Grid.Column>
</Grid.Row>
<Grid.Row>
<Grid.Column>
<ExperimentCard
Expand All @@ -334,9 +333,8 @@ export default class Home extends Component<Props, State> {
messy room.`}
/>
</Grid.Column>
</Grid.Row> */}

{/* <Grid.Row> */}
</Grid.Row>
{/* <Grid.Row>
<Grid.Column>
<ExperimentCard
onClick={() => this.handleNewExperiment(EXPERIMENTS.CUSTOM)}
Expand All @@ -347,7 +345,7 @@ export default class Home extends Component<Props, State> {
</Grid.Column>
<Grid.Column />
</Grid.Row>
</Grid.Row> */}
</Grid>
);
case HOME_STEPS.EXPLORE:
Expand Down
4 changes: 2 additions & 2 deletions app/constants/constants.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
export enum EXPERIMENTS {
NONE = 'NONE',
P300 = 'Visual Oddball',
N170 = 'Faces and Houses',
SSVEP = 'Steady-state Visual Evoked Potential',
STROOP = 'Stroop Task',
MULTI = 'Multi-tasking',
SEARCH = 'Visual Search',
CUSTOM = 'Custom',
// P300 = 'Visual Oddball',
// SSVEP = 'Steady-state Visual Evoked Potential',
}

export const SCREENS = {
Expand Down
25 changes: 12 additions & 13 deletions app/constants/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,32 +20,31 @@ export interface WorkSpaceInfo {

// All mutable aspects of an experiment that can be updated by the DesignComponent
export type ExperimentParameters = {
trialDuration: number;
nbTrials: number;
// TODO: consider refactoring to expose lab.js sample.mode
description?: ExperimentDescription;
intro: string;
iti: number;
jitter: number;
sampleType: string;
intro: string;
showProgressBar: boolean;
stimuli: Stimulus[];
nbPracticeTrials?: number;
// 'random' | 'sequential';
// TODO: consider refactoring to expose lab.js sample.mode
randomize?: string;
selfPaced?: boolean;
nbTrials: number;
presentationTime?: number;
randomize?: 'random' | 'sequential';
sampleType: string;
selfPaced?: boolean;
showProgressBar: boolean;
stimuli?: Stimulus[];
taskHelp?: string;
description: ExperimentDescription;
trialDuration: number;
};

export interface Stimulus {
condition?: string;
response?: string;
phase?: string;
type: EVENTS;
dir: string;
dir?: string;
title: string;
filename: string;
filename?: string;
}

interface ExperimentDescription {
Expand Down
26 changes: 15 additions & 11 deletions app/epics/jupyterEpics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ const loadEpochsEpic: Epic<JupyterActionType, JupyterActionType, RootState> = (
action$,
state$
) =>
// @ts-ignore
// @ts-expect-error
action$.pipe(
filter(isActionOf(JupyterActions.LoadEpochs)),
pluck('payload'),
Expand All @@ -166,18 +166,22 @@ const loadEpochsEpic: Epic<JupyterActionType, JupyterActionType, RootState> = (
awaitOkMessage(action$),
execute(filterIIR(1, 30), state$),
awaitOkMessage(action$),
map(() =>
epochEvents(
{
[state$.value.experiment.params!.stimulus1!.title]: EVENTS.STIMULUS_1,
[state$.value.experiment.params!.stimulus2!.title]: EVENTS.STIMULUS_2,
[state$.value.experiment.params!.stimulus3!.title]: EVENTS.STIMULUS_3,
[state$.value.experiment.params!.stimulus4!.title]: EVENTS.STIMULUS_4,
},
map(() => {
if (!state$.value.experiment.params?.stimuli) {
return {};
}

return epochEvents(
Object.fromEntries(
state$.value.experiment.params?.stimuli.map((stimulus, i) => [
stimulus.title,
i,
])
),
-0.1,
0.8
)
),
);
}),
tap((e) => {
console.log('e', e);
}),
Expand Down
2 changes: 1 addition & 1 deletion app/experiments/faces_houses/experiment.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* eslint-disable */
/* eslint-disable no-template-curly-in-string */

import {
initPracticeLoopWithStimuli,
Expand Down
8 changes: 7 additions & 1 deletion app/experiments/faces_houses/params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ const stimuli = Array.from({ length: 30 }, (_, i) => `Face${i + 1}`)
type: s.startsWith('Face') ? EVENTS.STIMULUS_1 : EVENTS.STIMULUS_2,
}));

/**
* NOTE: this params object may contain additional parameters in use by the experiment that are not
* explicitly defined in the ExperimentParameters interface, which explicitly defines parameters that can be tweaked
* in the current custom experiment UI.
* This inconsistency will likely be able to be fixed when updating to a lab.js builder-based experiment design flow
* */
export const params = {
imageHeight: '500px',
randomize: 'random',
Expand Down Expand Up @@ -62,4 +68,4 @@ export const params = {
// response: '9',
// },
stimuli,
};
} as const;
Loading

0 comments on commit 732a05b

Please sign in to comment.