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.

more than 2 markers

authored by

Yury Shevchenko and committed by
Teon L Brooks
9fcac874 46f06c50

+52 -48
+11 -3
app/components/AnalyzeComponent.js
··· 298 298 299 299 renderEpochLabels() { 300 300 if (!isNil(this.props.epochsInfo) && this.state.selectedFilePaths.length >= 1) { 301 + const numberConditions = (this.props.epochsInfo.filter( infoObj => (infoObj.name !== 'Drop Percentage' && infoObj.name !== 'Total Epochs'))).length; 302 + let colors; 303 + if(numberConditions === 4){ 304 + colors = ['red', 'yellow', 'green', 'blue']; 305 + } else { 306 + colors = ['red', 'green', 'teal', 'orange']; 307 + } 308 + console.log('numberConditions', numberConditions); 301 309 return ( 302 310 <div> 303 311 {this.props.epochsInfo ··· 305 313 .map((infoObj, index) => ( 306 314 <React.Fragment key={infoObj.name}> 307 315 <Header as="h4">{infoObj.name}</Header> 308 - <Icon name="circle" color={['red', 'orange', 'green', 'blue'][index]} /> 316 + <Icon name="circle" color={colors[index]} /> 309 317 {infoObj.value} 310 318 </React.Fragment> 311 319 ))} ··· 447 455 case ANALYZE_STEPS.BEHAVIOR: 448 456 return ( 449 457 <React.Fragment> 450 - <Grid.Column width={6}> 458 + <Grid.Column width={4}> 451 459 <Segment basic textAlign='left' className={styles.infoSegment}> 452 460 <Header as='h1'>Overview</Header> 453 461 <p>Load datasets from different subjects and view behavioral results</p> ··· 486 494 /> 487 495 </Segment> 488 496 </Grid.Column> 489 - <Grid.Column width={8} style={{ overflow: 'auto', maxHeight: 650 }}> 497 + <Grid.Column width={12} style={{ overflow: 'auto', maxHeight: 650, display: 'grid', justifyContent: 'center' }}> 490 498 <Segment basic textAlign='left' className={styles.plotSegment}> 491 499 <Plot data={this.state.dataToPlot} layout={this.state.layout} /> 492 500 <p />
+1 -1
app/components/DesignComponent/CustomDesignComponent.js
··· 639 639 }) 640 640 } 641 641 /> 642 - </Segment> : <Segment basic style={{'margin-bottom': '85px'}} />} 642 + </Segment> : <Segment basic style={{'marginBottom': '85px'}} />} 643 643 644 644 </Grid.Column> 645 645
+1
app/epics/jupyterEpics.js
··· 243 243 0.8 244 244 ) 245 245 ), 246 + tap((e)=> {console.log('e', e)}), 246 247 map((epochEventsCommand) => 247 248 state$.value.jupyter.mainChannel.next(executeRequest(epochEventsCommand)) 248 249 ),
+27 -33
app/utils/behavior/compute.js
··· 5 5 const processedData = data.map((result) => { 6 6 if (path.basename(result.meta.datafile).includes('aggregated')) { 7 7 return transformAggregated(result); 8 - } else { 9 - return filterData(result, removeOutliers); 10 8 } 9 + return filterData(result, removeOutliers); 10 + 11 11 }); 12 12 const aggregatedData = processedData.map((e) => { 13 13 const conditionsArray = e.map((row) => row.condition); 14 14 const unsortedConditions = [...new Set(conditionsArray)].sort(); 15 - const conditions = unsortedConditions.sort(function(a, b) { 16 - return parseInt(a) - parseInt(b); 17 - }); 15 + const conditions = unsortedConditions.sort((a, b) => parseInt(a) - parseInt(b)); 18 16 let rtMean = {}, 19 17 accuracyPercent = {}; 20 - for (let condition of conditions) { 21 - let rt = e 18 + for (const condition of conditions) { 19 + const rt = e 22 20 .filter((row) => row.response_given === 'yes') 23 21 .filter((row) => row.correct_response === 'true') 24 22 .filter((row) => row.condition === condition) 25 23 .map((row) => row.reaction_time) 26 24 .map((value) => parseFloat(value)); 27 25 rtMean[condition] = Math.round(ss.mean(rt)); 28 - let accuracy = e.filter( 26 + const accuracy = e.filter( 29 27 (row) => 30 28 row.condition === condition && 31 29 row.correct_response === 'true' && ··· 40 38 group: e.map((r) => r.group)[0], 41 39 session: e.map((r) => r.session)[0], 42 40 }; 43 - for (let condition of conditions) { 44 - row['RT_' + condition] = rtMean[condition]; 45 - row['Accuracy_' + condition] = accuracyPercent[condition]; 41 + for (const condition of conditions) { 42 + row[`RT_${ condition}`] = rtMean[condition]; 43 + row[`Accuracy_${ condition}`] = accuracyPercent[condition]; 46 44 } 47 45 return row; 48 46 }); ··· 65 63 }); 66 64 const colors = ['#28619E', '#3DBBDB']; 67 65 const unsortedConditions = [...new Set(processedData[0].map((row) => row.condition))].sort(); 68 - const conditions = unsortedConditions.sort(function(a, b) { 69 - return parseInt(a) - parseInt(b); 70 - }); 66 + const conditions = unsortedConditions.sort((a, b) => parseInt(a) - parseInt(b)); 71 67 switch (dependentVariable) { 72 68 case 'RT': 73 69 default: ··· 97 93 .filter((field) => field.startsWith('RT_')) 98 94 .map((c) => c.split('RT_')[1]) 99 95 .sort(); 100 - const conditions = unsortedConditions.sort(function(a, b) { 101 - return parseInt(a) - parseInt(b); 102 - }); 96 + const conditions = unsortedConditions.sort((a, b) => parseInt(a) - parseInt(b)); 103 97 const transformed = conditions.map((condition) => 104 98 result.data.map((e) => ({ 105 99 reaction_time: parseFloat(e[`RT_${condition}`]), ··· 118 112 119 113 const filterData = (data, removeOutliers) => { 120 114 let filteredData = data.data 121 - .filter((row) => row.trial_number) 115 + .filter((row) => row.trial_number && row.phase !== 'practice') 122 116 .map((row) => ({ 123 117 condition: row.condition, 124 118 subject: path.parse(data.meta.datafile).name.split('-')[0], ··· 259 253 .map((d) => { 260 254 if (d.filter((l) => l.accuracy).length > 0) { 261 255 return d.map((l) => l.accuracy); 262 - } else { 256 + } 263 257 const c = d.filter( 264 258 (e) => e.response_given === 'yes' && e.correct_response === 'true' 265 259 ); 266 260 return Math.round((c.length / d.length) * 100); 267 - } 261 + 268 262 }) 269 263 .reduce((acc, item) => acc.concat(item), []); 270 264 ··· 272 266 .map((d) => { 273 267 if (d.filter((l) => l.accuracy).length > 0) { 274 268 return d.map((l) => l.subject); 275 - } else { 276 - return d.map((r) => r.subject)[0]; 277 269 } 270 + return d.map((r) => r.subject)[0]; 271 + 278 272 }) 279 273 .reduce((acc, item) => acc.concat(item), []); 280 274 const subjects = Array.from(new Set(xRaw)); ··· 300 294 accuracy: l.accuracy, 301 295 subject: l.subject, 302 296 })); 303 - } else { 297 + } 304 298 const c = d.filter( 305 299 (e) => e.response_given === 'yes' && e.correct_response === 'true' 306 300 ); ··· 308 302 accuracy: Math.round((c.length / d.length) * 100), 309 303 subject: d.map((r) => r.subject)[0], 310 304 }; 311 - } 305 + 312 306 }) 313 307 .reduce((acc, item) => acc.concat(item), []); 314 308 const subjects = Array.from(new Set(transformedData.map((e) => e.subject))); ··· 318 312 const stErrorFunction = (array) => 319 313 ss.sampleStandardDeviation(array) / Math.sqrt(array.length); 320 314 const stErrors = subjects.map((subject) => { 321 - let array = transformedData.filter((e) => e.subject === subject).map((d) => d.accuracy); 315 + const array = transformedData.filter((e) => e.subject === subject).map((d) => d.accuracy); 322 316 if (array.length > 1) { 323 317 return stErrorFunction(array); 324 - } else { 318 + } 325 319 return 0; 326 - } 320 + 327 321 }); 328 322 obj[condition] = { x: subjects, y, stErrors }; 329 323 return obj; ··· 339 333 .map((d) => { 340 334 if (d.filter((l) => l.accuracy).length > 0) { 341 335 return d.map((l) => l.accuracy); 342 - } else { 336 + } 343 337 const c = d.filter( 344 338 (e) => e.response_given === 'yes' && e.correct_response === 'true' 345 339 ); 346 340 return Math.round((c.length / d.length) * 100); 347 - } 341 + 348 342 }) 349 343 .reduce((acc, item) => acc.concat(item), []); 350 344 const xRaw = correctDataForCondition 351 345 .map((d) => { 352 346 if (d.filter((l) => l.accuracy).length > 0) { 353 347 return d.map((l) => l.subject); 354 - } else { 355 - return d.map((r) => r.subject)[0]; 356 348 } 349 + return d.map((r) => r.subject)[0]; 350 + 357 351 }) 358 352 .reduce((acc, item) => acc.concat(item), []); 359 353 obj[condition] = { x: xRaw, y }; ··· 368 362 // Rendering functions 369 363 const makeDataPointsGraph = (data, conditions, colors, dependentVariable) => { 370 364 let dataForCondition; 371 - let symbols = ['circle', 'cross', 'diamond', 'square']; 365 + const symbols = ['circle', 'cross', 'diamond', 'square']; 372 366 const dataToPlot = conditions.map((condition, i) => { 373 367 dataForCondition = data[condition]; 374 368 return { ··· 440 434 }; 441 435 442 436 const makeBoxPlot = (data, conditions, colors, dependentVariable) => { 443 - let symbols = ['circle', 'cross', 'diamond', 'square']; 437 + const symbols = ['circle', 'cross', 'diamond', 'square']; 444 438 const dataToPlot = conditions.map((condition, i) => { 445 439 const dataForCondition = data[condition]; 446 440 return {
+2 -2
app/utils/labjs/protocols/custom.js
··· 38 38 randomize: 'random', 39 39 includePractice: true, 40 40 trialDuration: 1000, 41 - nbTrials: 8, 42 - nbPracticeTrials: 2, 41 + nbTrials: 0, 42 + nbPracticeTrials: 0, 43 43 iti: 500, 44 44 presentationTime: 1000, 45 45 selfPaced: true,
+10 -9
app/utils/labjs/scripts/multitasking.js
··· 1 1 import * as path from 'path'; 2 + 2 3 const rootFolder = __dirname; 3 4 const assetsDirectory = path.join(rootFolder, 'assets', 'labjs', 'multitasking'); 4 5 ··· 65 66 } 66 67 67 68 if (e.code === 'ArrowLeft' || e.code === 'ArrowRight') { 68 - let instructions = document.querySelectorAll('div.instruction'); 69 + const instructions = document.querySelectorAll('div.instruction'); 69 70 let notFound = true; 70 71 instructions.forEach((i) => { 71 72 if (i.style.display === 'block' && notFound) { 72 - let cur_id = parseInt(i.id.split('screen_')[1]); 73 + const cur_id = parseInt(i.id.split('screen_')[1]); 73 74 let next_id; 74 75 if (e.code === 'ArrowLeft') { 75 76 next_id = cur_id - 1; ··· 79 80 } 80 81 if (next_id > 0 && next_id <= 10) { 81 82 i.style.display = 'none'; 82 - next_id = 'screen_' + next_id; 83 + next_id = `screen_${ next_id}`; 83 84 document.querySelector(`#${next_id}`).style.display = 'block'; 84 85 notFound = false; 85 86 } ··· 1185 1186 messageHandlers: { 1186 1187 'before:prepare': function anonymous() { 1187 1188 function shuffle(a) { 1188 - var j, x, i; 1189 + let j, x, i; 1189 1190 for (i = a.length - 1; i > 0; i--) { 1190 1191 j = Math.floor(Math.random() * (i + 1)); 1191 1192 x = a[i]; ··· 1204 1205 function trialConstructor(block, dots, form, cor_response) { 1205 1206 return { 1206 1207 type: block, 1207 - dots: dots, 1208 - form: form, 1209 - cor_response: cor_response, 1208 + dots, 1209 + form, 1210 + cor_response, 1210 1211 }; 1211 1212 } 1212 1213 1213 1214 const numberBlocks = Math.ceil(this.parameters.num_trials / 4); 1214 1215 1215 1216 for (let i = 1; i <= numberBlocks; i++) { 1216 - for (let block of blocks) { 1217 + for (const block of blocks) { 1217 1218 if (block === 'shape') { 1218 1219 tasksParameters = tasksParameters.concat( 1219 1220 trialConstructor(block, 2, 'diamond', 'b') ··· 1940 1941 this.data.response_given = 1941 1942 this.state.correct === 'empty' ? 'no' : 'yes'; 1942 1943 } else { 1943 - this.data.response_given = 'practice'; 1944 + this.data.phase = 'practice'; 1944 1945 } 1945 1946 }, 1946 1947 },