MNE-CPP 0.1.9
A Framework for Electrophysiology
Loading...
Searching...
No Matches
butterflyview.cpp
Go to the documentation of this file.
1//=============================================================================================================
37//=============================================================================================================
38// INCLUDES
39//=============================================================================================================
40
41#include "butterflyview.h"
42
43#include "scalingview.h"
44
47
48//=============================================================================================================
49// QT INCLUDES
50//=============================================================================================================
51
52#include <QPainter>
53#include <QPainterPath>
54#include <QDebug>
55#include <QSvgGenerator>
56#include <QSurfaceFormat>
57#include <QSettings>
58
59//=============================================================================================================
60// USED NAMESPACES
61//=============================================================================================================
62
63using namespace DISPLIB;
64
65//=============================================================================================================
66// DEFINE MEMBER METHODS
67//=============================================================================================================
68
69ButterflyView::ButterflyView(const QString& sSettingsPath,
70 QWidget *parent,
71 Qt::WindowFlags f)
72:
73#if !defined(NO_QOPENGLWIDGET)
74 QOpenGLWidget(parent, f)
75#else
76 QWidget(parent, f)
77#endif
78, m_sSettingsPath(sSettingsPath)
79, m_pEvokedSetModel(NULL)
80, m_bIsInit(false)
81, m_bShowMAG(true)
82, m_bShowGRAD(true)
83, m_bShowEEG(true)
84, m_bShowEOG(true)
85, m_bShowMISC(true)
86, m_colCurrentBackgroundColor(Qt::white)
87, m_qMapAverageActivation(QSharedPointer<QMap<QString, bool> >::create())
88, m_qMapAverageColor(QSharedPointer<QMap<QString, QColor> >::create())
89{
90 m_sSettingsPath = sSettingsPath;
91// // Activate anti aliasing
92// QSurfaceFormat fmt;
93// fmt.setSamples(4);
94// this->setFormat(fmt);
96}
97
98//=============================================================================================================
99
104
105//=============================================================================================================
106
108{
109#if !defined(NO_QOPENGLWIDGET)
110 // Activate anti aliasing
111 initializeGL();
112#endif
113}
114
115//=============================================================================================================
116
117void ButterflyView::setEvokedSetModel(QSharedPointer<EvokedSetModel> model)
118{
119 m_pEvokedSetModel = model;
120
121 connect(m_pEvokedSetModel.data(), &EvokedSetModel::dataChanged,
122 this, &ButterflyView::dataUpdate, Qt::UniqueConnection);
123}
124
125//=============================================================================================================
126
128{
129 if(!m_bIsInit && m_pEvokedSetModel->isInit()) {
130 m_bIsInit = true;
131 }
132
134
135 update();
136}
137
138//=============================================================================================================
139
140QMap<QString, bool> ButterflyView::getModalityMap()
141{
142 return m_modalityMap;
143}
144
145//=============================================================================================================
146
147void ButterflyView::setModalityMap(const QMap<QString, bool> &modalityMap)
148{
149 m_modalityMap = modalityMap;
150 update();
151}
152
153//=============================================================================================================
154
155void ButterflyView::setScaleMap(const QMap<qint32,float> &scaleMap)
156{
157 m_scaleMap = scaleMap;
158 update();
159}
160
161//=============================================================================================================
162
163void ButterflyView::setSelectedChannels(const QList<int> &selectedChannels)
164{
165 m_lSelectedChannels = selectedChannels;
166 update();
167}
168
169//=============================================================================================================
170
172{
173 update();
174}
175
176//=============================================================================================================
177
178void ButterflyView::setBackgroundColor(const QColor& backgroundColor)
179{
180 m_colCurrentBackgroundColor = backgroundColor;
181 update();
182}
183
184//=============================================================================================================
185
190
191//=============================================================================================================
192
193void ButterflyView::takeScreenshot(const QString& fileName)
194{
195 if(fileName.contains(".svg", Qt::CaseInsensitive)) {
196 // Generate screenshot
197 QSvgGenerator svgGen;
198 svgGen.setFileName(fileName);
199 svgGen.setSize(this->size());
200 svgGen.setViewBox(this->rect());
201
202 this->render(&svgGen);
203 }
204
205 if(fileName.contains(".png", Qt::CaseInsensitive)) {
206 QImage image(this->size(), QImage::Format_ARGB32);
207 image.fill(Qt::transparent);
208
209 QPainter painter(&image);
210 this->render(&painter);
211 image.save(fileName);
212 }
213}
214
215//=============================================================================================================
216
217QSharedPointer<QMap<QString, QColor> > ButterflyView::getAverageColor() const
218{
219 return m_qMapAverageColor;
220}
221
222//=============================================================================================================
223
224QSharedPointer<QMap<QString, bool> > ButterflyView::getAverageActivation() const
225{
227}
228
229//=============================================================================================================
230
231void ButterflyView::setAverageColor(const QSharedPointer<QMap<QString, QColor> > qMapAverageColor)
232{
233 m_qMapAverageColor = qMapAverageColor;
234 update();
235}
236
237//=============================================================================================================
238
239void ButterflyView::setSingleAverageColor(const QColor& avgColor)
240{
241 for (QString mapKey : m_qMapAverageColor->keys())
242 m_qMapAverageColor->insert(mapKey, avgColor);
243}
244
245//=============================================================================================================
246
247void ButterflyView::setAverageActivation(const QSharedPointer<QMap<QString, bool> > qMapAverageActivation)
248{
249 m_qMapAverageActivation = qMapAverageActivation;
250 update();
251}
252
253//=============================================================================================================
254
255void ButterflyView::setChannelInfoModel(QSharedPointer<ChannelInfoModel> &pChannelInfoModel)
256{
257 m_pChannelInfoModel = pChannelInfoModel;
258}
259
260//=============================================================================================================
261
262void ButterflyView::showSelectedChannelsOnly(const QStringList& selectedChannels)
263{
265 qDebug() << "ButterflyView::showSelectedChannelsOnly - m_pChannelInfoModel is NULL. Returning. ";
266 return;
267 }
268
269 QList<int> selectedChannelsIndexes;
270
271 for(int i = 0; i<selectedChannels.size(); i++)
272 selectedChannelsIndexes<<m_pChannelInfoModel->getIndexFromOrigChName(selectedChannels.at(i));
273
274 setSelectedChannels(selectedChannelsIndexes);
275}
276
277//=============================================================================================================
278
279void ButterflyView::showSelectedChannels(const QList<int> selectedChannelsIndexes)
280{
281 setSelectedChannels(selectedChannelsIndexes);
282}
283
284//=============================================================================================================
285
287{
288 if (m_pEvokedSetModel) {
289 QList<int> lAllChannels;
290 for(int i = 0; i < m_pEvokedSetModel->rowCount(); i++) {
291 lAllChannels.append(i);
292 }
293 setSelectedChannels(lAllChannels);
294 }
295}
296
297//=============================================================================================================
298
300{
301 if(m_sSettingsPath.isEmpty()) {
302 return;
303 }
304
305 // Save Settings
306 QSettings settings("MNECPP");
307}
308
309//=============================================================================================================
310
312{
313 if(m_sSettingsPath.isEmpty()) {
314 return;
315 }
316
317 // Load Settings
318 QSettings settings("MNECPP");
319}
320
321//=============================================================================================================
322
323#if !defined(NO_QOPENGLWIDGET)
325#else
326 void ButterflyView::paintEvent(QPaintEvent *event)
327#endif
328{
329 QPainter painter(this);
330
331 painter.save();
332 painter.setBrush(QBrush(m_colCurrentBackgroundColor));
333 painter.drawRect(QRect(-1,-1,this->width()+2,this->height()+2));
334 painter.restore();
335
336 painter.setRenderHint(QPainter::Antialiasing, true);
337
338 if(m_bIsInit && m_pEvokedSetModel)
339 {
340 //Draw baseline correction area
341 if(m_pEvokedSetModel->getBaselineInfo().first.toString() != "None" &&
342 m_pEvokedSetModel->getBaselineInfo().second.toString() != "None") {
343 float from = m_pEvokedSetModel->getBaselineInfo().first.toFloat();
344 float to = m_pEvokedSetModel->getBaselineInfo().second.toFloat();
345
346 painter.save();
347 painter.setPen(QPen(Qt::red, 1, Qt::DashLine));
348 painter.setBrush(Qt::red);
349 painter.setOpacity(0.1);
350
351 if(m_pEvokedSetModel->getNumSamples() == 0){
352 qDebug() << "Unable to get data. Returning early.";
353 return;
354 }
355
356 float fDx = (float)(this->width()) / ((float)m_pEvokedSetModel->getNumSamples());
357
358 float fromSamp = ((from)*m_pEvokedSetModel->getSamplingFrequency())+m_pEvokedSetModel->getNumPreStimSamples();
359 float posX = fDx*(fromSamp);
360 float toSamp = ((to)*m_pEvokedSetModel->getSamplingFrequency())+m_pEvokedSetModel->getNumPreStimSamples();
361 float width = fDx*(toSamp-fromSamp);
362
363 QRect rect(posX,0,width,this->height());
364
365 painter.drawRect(rect);
366
367 painter.restore();
368 }
369
370 //Stimulus bar
371 if(m_pEvokedSetModel->getNumSamples() > 0) {
372 painter.save();
373 painter.setPen(QPen(Qt::red, 1, Qt::DashLine));
374
375 float fDx = (float)(this->width()) / ((float)m_pEvokedSetModel->getNumSamples());
376 float posX = fDx * ((float)m_pEvokedSetModel->getNumPreStimSamples());
377 painter.drawLine(posX, 1, posX, this->height());
378
379 painter.drawText(QPointF(posX+5,this->rect().bottomRight().y()-5), QString("0ms / Stimulus"));
380
381 painter.restore();
382 }
383
384 //Vertical time spacers
385 if(m_pEvokedSetModel->getNumberOfTimeSpacers() > 0)
386 {
387 painter.save();
388 QColor colorTimeSpacer = Qt::black;
389 colorTimeSpacer.setAlphaF(0.5);
390 painter.setPen(QPen(colorTimeSpacer, 1, Qt::DashLine));
391
392 float yStart = this->rect().topLeft().y();
393 float yEnd = this->rect().bottomRight().y();
394
395 float fDx = 1;
396 if(m_pEvokedSetModel->getNumSamples() != 0) {
397 fDx = (float)(this->width()) / ((float)m_pEvokedSetModel->getNumSamples());
398 }
399
400 float sampleCounter = m_pEvokedSetModel->getNumPreStimSamples();
401 int counter = 1;
402 float timeDistanceMSec = 50.0;
403 float timeDistanceSamples = (timeDistanceMSec/1000.0)*m_pEvokedSetModel->getSamplingFrequency(); //time distance corresponding to sampling frequency
404
405 //spacers before stim
406 while(sampleCounter-timeDistanceSamples>0) {
407 sampleCounter-=timeDistanceSamples;
408 float x = fDx*sampleCounter;
409 painter.drawLine(x, yStart, x, yEnd);
410 painter.drawText(QPointF(x+5,yEnd-5), QString("-%1ms").arg(timeDistanceMSec*counter));
411 counter++;
412 }
413
414 //spacers after stim
415 counter = 1;
416 sampleCounter = m_pEvokedSetModel->getNumPreStimSamples();
417 while(sampleCounter+timeDistanceSamples<m_pEvokedSetModel->getNumSamples()) {
418 sampleCounter+=timeDistanceSamples;
419 float x = fDx*sampleCounter;
420 painter.drawLine(x, yStart, x, yEnd);
421 painter.drawText(QPointF(x+5,yEnd-5), QString("%1ms").arg(timeDistanceMSec*counter));
422 counter++;
423 }
424
425 painter.restore();
426 }
427
428 //Zero line
429 if(m_pEvokedSetModel->getNumSamples() > 0) {
430 painter.save();
431 painter.setPen(QPen(Qt::black, 1, Qt::DashLine));
432
433 painter.drawLine(0, this->height()/2, this->width(), this->height()/2);
434
435 painter.restore();
436 }
437
438 painter.translate(0,this->height()/2);
439
440 //Actual average data
441 for(qint32 r = 0; r < m_pEvokedSetModel->rowCount(); ++r) {
442 if(m_lSelectedChannels.contains(r)) {
443 qint32 kind = m_pEvokedSetModel->getKind(r);
444
445 //Display only selected kinds
446 switch(kind) {
447 case FIFFV_MEG_CH: {
448 qint32 unit = m_pEvokedSetModel->getUnit(r);
449 if(unit == FIFF_UNIT_T_M) {
450 if(m_modalityMap["GRAD"])
451 break;
452 else
453 continue;
454 }
455 else if(unit == FIFF_UNIT_T)
456 {
457 if(m_modalityMap["MAG"])
458 break;
459 else
460 continue;
461 }
462 continue;
463 }
464 case FIFFV_EEG_CH: {
465 if(m_modalityMap["EEG"])
466 break;
467 else
468 continue;
469 }
470 case FIFFV_EOG_CH: {
471 if(m_modalityMap["EOG"])
472 break;
473 else
474 continue;
475 }
476 case FIFFV_MISC_CH: {
477 if(m_modalityMap["MISC"])
478 break;
479 else
480 continue;
481 }
482 default:
483 continue;
484 }
485
486 painter.save();
487
488 createPlotPath(r, painter);
489
490 painter.restore();
491 }
492 }
493 }
494
495#if !defined(NO_QOPENGLWIDGET)
496 return QOpenGLWidget::paintGL();
497#else
498 return QWidget::paintEvent(event);
499#endif
500}
501
502//=============================================================================================================
503
504void ButterflyView::createPlotPath(qint32 row, QPainter& painter) const
505{
506 //get maximum range of respective channel type (range value in FiffChInfo does not seem to contain a reasonable value)
507 qint32 kind = m_pEvokedSetModel->getKind(row);
508 float fMaxValue = DISPLIB::getScalingValue(m_scaleMap, kind, m_pEvokedSetModel->getUnit(row));
509 bool bIsBad = m_pEvokedSetModel->getIsChannelBad(row);
510
511 if(bIsBad) {
512 painter.setOpacity(0.20);
513 } else {
514 painter.setOpacity(0.75);
515 }
516
517 float fValue;
518 float fScaleY = this->height()/(2*fMaxValue);
519
520 //restrictions for paint performance
521 float fWinMaxVal = ((float)this->height()-2)/2.0f;
522// qint32 iDownSampling = (m_pEvokedSetModel->getNumSamples() * 4 / (this->width()-2));
523// if(iDownSampling < 1) {
524// iDownSampling = 1;
525// }
526
527 QPointF qSamplePosition;
528
529 float fDx = (float)(this->width()-2) / ((float)m_pEvokedSetModel->getNumSamples()-1.0f);//((float)option.rect.width()) / m_pEvokedSetModel->getMaxSamples();
530
531 QList<DISPLIB::AvrTypeRowVector> rowVec = m_pEvokedSetModel->data(row,1).value<QList<DISPLIB::AvrTypeRowVector> >();
532
533 //Do for all average types
534 for(int j = 0; j < rowVec.size(); ++j) {
535 QString sAvrComment = rowVec.at(j).first;
536
537 // Select color for each average
538 if(m_pEvokedSetModel->isFreezed()) {
539 QColor freezeColor = m_qMapAverageColor->value(sAvrComment);
540 freezeColor.setAlphaF(0.5);
541 painter.setPen(QPen(freezeColor, 1));
542 } else {
543 painter.setPen(QPen(m_qMapAverageColor->value(sAvrComment)));
544 }
545
546 if(m_qMapAverageActivation->value(sAvrComment)) {
547 //Calculate downsampling factor of averaged data in respect to the items width
548 int dsFactor;
549 rowVec.at(j).second.cols() / this->width() < 1 ? dsFactor = 1 : dsFactor = rowVec.at(j).second.cols() / this->width();
550 if(dsFactor == 0) {
551 dsFactor = 1;
552 }
553
554 QPainterPath path(QPointF(1,0));
555 float y_base = path.currentPosition().y();
556
557 //Move to initial starting point
558 if(rowVec.at(j).second.cols() > 0)
559 {
560 float val = rowVec.at(j).second[0];
561 fValue = (val/*-rowVec.at(j)[m_pEvokedSetModel->getNumPreStimSamples()-1]*/)*fScaleY;//ToDo -> -2 PreStim is one too short
562
563 float newY = y_base+fValue;
564
565 qSamplePosition.setY(-newY);
566 qSamplePosition.setX(path.currentPosition().x());
567
568 path.moveTo(qSamplePosition);
569 }
570
571 //create lines from one to the next sample
572 qint32 i;
573 for(i = 1; i < rowVec.at(j).second.cols() && path.elementCount() <= this->width(); i += dsFactor) {
574 float val = /*rowVec.at(j)[m_pEvokedSetModel->getNumPreStimSamples()-1] - */rowVec.at(j).second[i]; //remove first sample data[0] as offset
575 fValue = val*fScaleY;
576
577 //Cut plotting if out of widget area
578 fValue = fValue > fWinMaxVal ? fWinMaxVal : fValue < -fWinMaxVal ? -fWinMaxVal : fValue;
579
580 float newY = y_base+fValue;
581
582 qSamplePosition.setY(-newY);
583
584 qSamplePosition.setX(path.currentPosition().x()+fDx);
585
586 path.lineTo(qSamplePosition);
587 }
588
589 // //create lines from one to the next sample for last path
590 // qint32 sample_offset = m_pEvokedSetModel->numVLines() + 1;
591 // qSamplePosition.setX(qSamplePosition.x() + fDx*sample_offset);
592 // lastPath.moveTo(qSamplePosition);
593
594 // for(i += sample_offset; i < lastData.size(); ++i) {
595 // float val = lastData[i] - lastData[0]; //remove first sample lastData[0] as offset
596 // fValue = val*fScaleY;
597
598 // float newY = y_base+fValue;
599
600 // qSamplePosition.setY(newY);
601 // qSamplePosition.setX(lastPath.currentPosition().x()+fDx);
602
603 // lastPath.lineTo(qSamplePosition);
604 // }
605
606 painter.drawPath(path);
607 }
608 }
609}
610
611//=============================================================================================================
612
613QSharedPointer<EvokedSetModel> ButterflyView::getEvokedSetModel()
614{
615 return m_pEvokedSetModel;
616}
617
618//=============================================================================================================
619
621{
622 setEvokedSetModel(Q_NULLPTR);
623}
Declaration of the ScalingView Class.
DISPSHARED_EXPORT float getScalingValue(const QMap< qint32, float > &qMapChScaling, int iChannelKind, int iChannelUnit)
Declaration of the ButterflyView class.
The declaration for ChannelInfoModel..
Declaration of the EvokedSetModel Class.
QSharedPointer< QMap< QString, bool > > m_qMapAverageActivation
QSharedPointer< EvokedSetModel > m_pEvokedSetModel
QList< int > m_lSelectedChannels
void createPlotPath(qint32 row, QPainter &painter) const
void setChannelInfoModel(QSharedPointer< ChannelInfoModel > &pChannelInfoModel)
QSharedPointer< QMap< QString, QColor > > getAverageColor() const
void setModalityMap(const QMap< QString, bool > &modalityMap)
void takeScreenshot(const QString &fileName)
QMap< QString, bool > getModalityMap()
const QColor & getBackgroundColor()
void setAverageColor(const QSharedPointer< QMap< QString, QColor > > qMapAverageColor)
void showSelectedChannels(const QList< int > selectedChannelsIndexes)
void setSelectedChannels(const QList< int > &selectedChannels)
QSharedPointer< ChannelInfoModel > m_pChannelInfoModel
QSharedPointer< QMap< QString, QColor > > m_qMapAverageColor
QSharedPointer< QMap< QString, bool > > getAverageActivation() const
void setEvokedSetModel(QSharedPointer< EvokedSetModel > model)
void setSingleAverageColor(const QColor &avgColor)
void setBackgroundColor(const QColor &backgroundColor)
void showSelectedChannelsOnly(const QStringList &selectedChannels)
void setScaleMap(const QMap< qint32, float > &scaleMap)
QMap< qint32, float > m_scaleMap
ButterflyView(const QString &sSettingsPath="", QWidget *parent=0, Qt::WindowFlags f=Qt::Widget)
QSharedPointer< EvokedSetModel > getEvokedSetModel()
QMap< QString, bool > m_modalityMap
void setAverageActivation(const QSharedPointer< QMap< QString, bool > > qMapAverageActivation)