An easy-to-use platform for EEG experimentation in the classroom
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

updates to the behavior analysis screen

Co-Authored-By: Yury-Shevchenko <shevchenko_yury@mail.ru>

+32 -21
+11 -7
app/components/AnalyzeComponent.js
··· 33 33 import HelpSidebar from './CollectComponent/HelpSidebar'; 34 34 35 35 const ANALYZE_STEPS = { 36 + BEHAVIOR: 'BEHAVIOR', 36 37 OVERVIEW: 'OVERVIEW', 37 - ERP: 'ERP', 38 - BEHAVIOR: 'BEHAVIOR' 38 + ERP: 'ERP' 39 + }; 40 + 41 + const ANALYZE_STEPS_BEHAVIOR = { 42 + BEHAVIOR: 'BEHAVIOR', 39 43 }; 40 44 41 45 interface Props { ··· 97 101 constructor(props: Props) { 98 102 super(props); 99 103 this.state = { 100 - activeStep: ANALYZE_STEPS.OVERVIEW, 104 + activeStep: ANALYZE_STEPS.BEHAVIOR, 101 105 eegFilePaths: [{ key: '', text: '', value: '' }], 102 106 behaviorFilePaths: [{ key: '', text: '', value: '' }], 103 107 dependentVariables: [{ key: '', text: '', value: '' }], 104 108 dataToPlot:[], 105 109 layout: {}, 106 110 selectedDependentVariable: '', 107 - removeOutliers: false, 111 + removeOutliers: true, 108 112 showDataPoints: false, 109 113 isSidebarVisible: false, 110 114 // displayOutlierVisible: false, 111 - displayMode: 'datapoints', 112 - helpMode: 'datapoints', 115 + displayMode: 'errorbars', 116 + helpMode: 'errorbars', 113 117 selectedFilePaths: [], 114 118 selectedSubjects: [], 115 119 selectedChannel: ··· 572 576 <div className={styles.mainContainer}> 573 577 <SecondaryNavComponent 574 578 title="Analyze" 575 - steps={ANALYZE_STEPS} 579 + steps={this.props.isEEGEnabled === true ? ANALYZE_STEPS : ANALYZE_STEPS_BEHAVIOR} 576 580 activeStep={this.state.activeStep} 577 581 onStepClick={this.handleStepClick} 578 582 />
+16 -12
app/utils/behavior/compute.js
··· 11 11 const aggregatedData = processedData 12 12 .map(e => { 13 13 const conditionsArray = e.map(row => row.condition); 14 - const conditions = [... new Set(conditionsArray)]; 14 + const unsortedConditions = [... new Set(conditionsArray)].sort(); 15 + const conditions = unsortedConditions.sort(function(a, b){return parseInt(a)-parseInt(b)}); 15 16 let rtMean = {}, accuracyPercent = {}; 16 17 for(let condition of conditions){ 17 18 let rt = e ··· 25 26 .filter(row => row.condition === condition && row.correct_response === 'true' && row.response_given === 'yes') 26 27 accuracyPercent[condition] = accuracy.length ? Math.round(100 * (accuracy.length / e.filter(r => r.condition === condition ).length)) : ss.mean(e.filter(r => r.condition === condition).map(r => r.accuracy)); 27 28 } 28 - return { 29 + const row = { 29 30 subject: e.map(r => r.subject)[0], 30 31 session: e.map(r => r.session)[0], 31 - [`RT_${conditions[0]}`]: rtMean[conditions[0]], 32 - [`RT_${conditions[1]}`]: rtMean[conditions[1]], 33 - [`Accuracy_${conditions[0]}`]: accuracyPercent[conditions[0]], 34 - [`Accuracy_${conditions[1]}`]: accuracyPercent[conditions[1]], 35 32 response_given: 'yes', 36 33 correct_response: 'true' 37 34 } 35 + for(let condition of conditions){ 36 + row['RT_' + condition] = rtMean[condition]; 37 + row['Accuracy_' + condition] = accuracyPercent[condition]; 38 + } 39 + return row; 38 40 }) 39 41 return aggregatedData; 40 42 }; ··· 49 51 50 52 }); 51 53 const colors = ['#28619E','#3DBBDB']; 52 - const conditions = [... new Set(processedData[0].map(row => row.condition))]; 54 + const unsortedConditions = [... new Set(processedData[0].map(row => row.condition))].sort(); 55 + const conditions = unsortedConditions.sort(function(a, b){return parseInt(a)-parseInt(b)}); 53 56 switch (dependentVariable) { 54 57 case "RT": 55 58 default: ··· 61 64 }; 62 65 63 66 const transformAggregated = (result) => { 64 - const conditions = result.meta.fields.filter(field => field.startsWith('RT_')).map(c => c.split('RT_')[1]); 67 + const unsortedConditions = result.meta.fields.filter(field => field.startsWith('RT_')).map(c => c.split('RT_')[1]).sort(); 68 + const conditions = unsortedConditions.sort(function(a, b){return parseInt(a)-parseInt(b)}); 65 69 const transformed = conditions.map((condition) => result.data.map(e => ({ 66 70 reaction_time: parseFloat(e[`RT_${condition}`]), 67 71 subject: result.meta.datafile.split('/').pop().split('.csv')[0], ··· 142 146 return obj; 143 147 }, {}) 144 148 dataToPlot['lowerLimit'] = 0; 145 - dataToPlot['upperLimit'] = maxValue > 1000 ? maxValue + maxValueSE + 100 : 1000; 149 + dataToPlot['upperLimit'] = maxValue + maxValueSE > 1000 ? maxValue + maxValueSE + 100 : 1000; 146 150 return makeBarGraph(dataToPlot, conditions, colors, dependentVariable) 147 151 148 152 case "whiskers": ··· 287 291 ticktext: data.ticktext, 288 292 }, 289 293 yaxis: { 290 - title: `${dependentVariable == 'Response Time' ? 'ms.' : '% correct'}`, 294 + title: `${dependentVariable == 'Response Time' ? 'Response Time (milliseconds)' : '% correct'}`, 291 295 range: [data.lowerLimit, data.upperLimit], 292 296 }, 293 297 title: `${dependentVariable}` ··· 319 323 }) 320 324 const layout = { 321 325 yaxis: { 322 - title: `${dependentVariable == 'Response Time' ? 'ms.' : '% correct'}`, 326 + title: `${dependentVariable == 'Response Time' ? 'Response Time (milliseconds)' : '% correct'}`, 323 327 zeroline: false, 324 328 range: [data.lowerLimit, data.upperLimit], 325 329 }, ··· 352 356 }) 353 357 const layout = { 354 358 yaxis: { 355 - title: `${dependentVariable == 'Response Time' ? 'ms.' : '% correct'}`, 359 + title: `${dependentVariable == 'Response Time' ? 'Response Time (milliseconds)' : '% correct'}`, 356 360 zeroline: false, 357 361 range: [data.lowerLimit, data.upperLimit], 358 362 },
+3 -1
app/utils/filesystem/storage.js
··· 43 43 csv: string, 44 44 title: string, 45 45 subject: string, 46 + group: string, 46 47 session: number 47 48 ) => { 49 + console.log('storing group', group); 48 50 const dir = path.join(getWorkspaceDir(title), 'Data', subject, 'Behavior'); 49 - const filename = `${subject}-${session}-behavior.csv`; 51 + const filename = `${subject}-${group}-${session}-behavior.csv`; 50 52 mkdirPathSync(dir); 51 53 fs.writeFile(path.join(dir, filename), csv, err => { 52 54 if (err) {
+2 -1
app/utils/filesystem/write.js
··· 15 15 export const createEEGWriteStream = ( 16 16 title: string, 17 17 subject: string, 18 + group: string, 18 19 session: number 19 20 ) => { 20 21 try { 21 22 const dir = path.join(getWorkspaceDir(title), "Data", subject, "EEG"); 22 - const filename = `${subject}-${session}-raw.csv`; 23 + const filename = `${subject}-${group}-${session}-raw.csv`; 23 24 mkdirPathSync(dir); 24 25 return fs.createWriteStream(path.join(dir, filename)); 25 26 } catch (e) {