@@ -496,6 +496,43 @@ require('./jquery.timer');
496496var Highcharts = require('highcharts');
497497var HighchartsAnnotations = require('highcharts-annotations')(Highcharts);
498498
499+ var frequencyBandVisualizationDefault = {
500+ bands: [
501+ {
502+ name: 'Delta',
503+ frequency: {
504+ min: 1,
505+ max: 4,
506+ },
507+ color: '#F77C00', // orange
508+ },
509+ {
510+ name: 'Mixed Freq.',
511+ frequency: {
512+ min: 4,
513+ max: 8,
514+ },
515+ color: '#25C700', // green
516+ },
517+ {
518+ name: 'Alpha',
519+ frequency: {
520+ min: 8,
521+ max: 13,
522+ },
523+ color: '#1968FF', // blue
524+ },
525+ {
526+ name: 'Beta',
527+ frequency: {
528+ min: 13,
529+ max: 30,
530+ },
531+ color: '#000000', // black
532+ },
533+ ],
534+ };
535+
499536$.widget('crowdcurio.TimeSeriesAnnotator', {
500537
501538 options: {
@@ -564,6 +601,15 @@ $.widget('crowdcurio.TimeSeriesAnnotator', {
564601 showReferenceLines: true,
565602 showTimeLabels: true,
566603 showChannelNames: true,
604+ frequencyBandVisualizationPerChannel: [
605+ frequencyBandVisualizationDefault,
606+ frequencyBandVisualizationDefault,
607+ frequencyBandVisualizationDefault,
608+ undefined,
609+ undefined,
610+ undefined,
611+ undefined,
612+ ],
567613 features: {
568614 examplesModeEnabled: false,
569615 examples: [{
@@ -2245,11 +2291,16 @@ $.widget('crowdcurio.TimeSeriesAnnotator', {
22452291 gain: input.channel_gains[i],
22462292 values: input.channel_values[name]
22472293 }
2294+ if (input.channel_stft_values_absolute && input.channel_stft_values_absolute[i]) {
2295+ channel.stftValuesAbsolute = input.channel_stft_values_absolute[i];
2296+ }
22482297 channels.push(channel);
22492298 }
22502299 var output = {
22512300 channels: channels,
2252- sampling_rate: input.sampling_rate
2301+ sampling_rate: input.sampling_rate,
2302+ stft_sample_frequencies: input.stft_sample_frequencies,
2303+ stft_segment_times: input.stft_segment_times,
22532304 }
22542305 return output;
22552306 },
@@ -2298,13 +2349,19 @@ $.widget('crowdcurio.TimeSeriesAnnotator', {
22982349 for(var ii=0; ii<data.channels.length; ii++) {
22992350 var channel = data.channels[ii];
23002351
2301- that.vars.chart.series[ii].update( {
2352+ var channelUpdate = {
23022353 pointStart: that.vars.currentWindowStart,
23032354 pointInterval: 1 / data.sampling_rate,
23042355 name: channel.name,
23052356 type: 'line',
23062357 data: channel.values
2307- }, false); // false to supress redrawing after every series is added
2358+ };
2359+ var channelColor = that._getChannelColor(data, ii);
2360+ if (channelColor) {
2361+ channelUpdate.color = channelColor;
2362+ }
2363+
2364+ that.vars.chart.series[ii].update(channelUpdate, false); // false to supress redrawing after every series is added
23082365 }
23092366 that.vars.chart.xAxis[0].setExtremes(that.vars.currentWindowStart, that.vars.currentWindowStart + that.options.windowSizeInSeconds, false, false);
23102367 that.vars.chart.redraw(); // efficiently redraw the entire window in one go
@@ -2356,9 +2413,6 @@ $.widget('crowdcurio.TimeSeriesAnnotator', {
23562413 title: {
23572414 text: ''
23582415 },
2359- tooltip: {
2360- enabled: false
2361- },
23622416 plotOptions: {
23632417 series: {
23642418 animation: false,
@@ -3060,11 +3114,87 @@ $.widget('crowdcurio.TimeSeriesAnnotator', {
30603114 type: 'line',
30613115 data: channels[ii].values
30623116 };
3117+ var channelColor = that._getChannelColor(data, ii);
3118+ if (channelColor) {
3119+ channel.color = channelColor;
3120+ channel.enableMouseTracking = true;
3121+ channel.stickyTracking = false;
3122+ channel.tooltip = that._getChannelTooltip(data, ii);
3123+ }
30633124 series.push(channel);
30643125 }
30653126 return(series);
30663127 },
30673128
3129+ _getChannelColor: function(data, channelIndex) {
3130+ var that = this;
3131+ var frequencyBandVisualization = that.options.frequencyBandVisualizationPerChannel[channelIndex];
3132+ if (!frequencyBandVisualization) {
3133+ return;
3134+ }
3135+ var bands = frequencyBandVisualization.bands;
3136+ var bandsFrequencyIndices = [];
3137+ bands.forEach(function(band) {
3138+ var frequencyIndexStart = 0;
3139+ var frequencyIndexEnd = data.stft_sample_frequencies.length - 1;
3140+ for (var f = 0; f < data.stft_sample_frequencies.length; ++f) {
3141+ if (data.stft_sample_frequencies[f] > band.frequency.min) {
3142+ frequencyIndexStart = f;
3143+ break;
3144+ }
3145+ }
3146+ for (var f = data.stft_sample_frequencies.length - 1; f >= 0; --f) {
3147+ if (data.stft_sample_frequencies[f] <= band.frequency.max) {
3148+ frequencyIndexEnd = f;
3149+ break;
3150+ }
3151+ }
3152+ bandsFrequencyIndices.push({
3153+ start: frequencyIndexStart,
3154+ end: frequencyIndexEnd,
3155+ });
3156+ });
3157+ var stftValuesAbsolute = data.channels[channelIndex].stftValuesAbsolute;
3158+ var stops = stftValuesAbsolute.map(function(frequencySamples, t) {
3159+ var frequencyPowersAggregates = bandsFrequencyIndices.map(function(bandFrequencyIndices) {
3160+ var frequencyPowers = frequencySamples.slice(bandFrequencyIndices.start, bandFrequencyIndices.end + 1)
3161+ var frequencyPowersSum = frequencyPowers.reduce(function(a, b) { return a + b; }, 0);
3162+ return frequencyPowersSum / frequencyPowers.length;
3163+ });
3164+ var dominantBandIndex = frequencyPowersAggregates.indexOf(Math.max.apply(Math, frequencyPowersAggregates));
3165+ var dominantBand = bands[dominantBandIndex];
3166+ var timeStepRelative = t / (stftValuesAbsolute.length - 1);
3167+ return [ timeStepRelative, dominantBand.color ];
3168+ });
3169+ var channelColor = {
3170+ linearGradient: { x1: 0, y1: 0, x2: 1, y2: 0 },
3171+ stops: stops,
3172+ };
3173+ return channelColor;
3174+ },
3175+
3176+ _getChannelTooltip: function(data, channelIndex) {
3177+ var that = this;
3178+ var frequencyBandVisualization = that.options.frequencyBandVisualizationPerChannel[channelIndex];
3179+ if (!frequencyBandVisualization) {
3180+ return;
3181+ }
3182+ var bands = frequencyBandVisualization.bands;
3183+ var pointFormat = 'Rhythms:';
3184+ bands.forEach(function(band) {
3185+ pointFormat += '<span style="color: ' + band.color + '; font-weight: bold"> ' + band.name + ' (' + band.frequency.min + ' - ' + band.frequency.max + ' Hz)</span>';
3186+ });
3187+ var tooltip = {
3188+ enabled: true,
3189+ split: true,
3190+ useHTML: true,
3191+ headerFormat: '',
3192+ pointFormat: pointFormat,
3193+ footerFormat: '',
3194+ };
3195+ return tooltip;
3196+ },
3197+
30683198 _getFeatureColor: function(featureKey, isAnswer, confidence) {
30693199 var that = this;
30703200 var isAnswer = !!isAnswer;
0 commit comments