MNE-CPP  0.1.9
A Framework for Electrophysiology
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 
45 #include "helpers/evokedsetmodel.h"
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 
63 using namespace DISPLIB;
64 
65 //=============================================================================================================
66 // DEFINE MEMBER METHODS
67 //=============================================================================================================
68 
69 ButterflyView::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);
95  loadSettings();
96 }
97 
98 //=============================================================================================================
99 
101 {
102  saveSettings();
103 }
104 
105 //=============================================================================================================
106 
108 {
109 #if !defined(NO_QOPENGLWIDGET)
110  // Activate anti aliasing
111  initializeGL();
112 #endif
113 }
114 
115 //=============================================================================================================
116 
117 void 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 
140 QMap<QString, bool> ButterflyView::getModalityMap()
141 {
142  return m_modalityMap;
143 }
144 
145 //=============================================================================================================
146 
147 void ButterflyView::setModalityMap(const QMap<QString, bool> &modalityMap)
148 {
149  m_modalityMap = modalityMap;
150  update();
151 }
152 
153 //=============================================================================================================
154 
155 void ButterflyView::setScaleMap(const QMap<qint32,float> &scaleMap)
156 {
157  m_scaleMap = scaleMap;
158  update();
159 }
160 
161 //=============================================================================================================
162 
163 void ButterflyView::setSelectedChannels(const QList<int> &selectedChannels)
164 {
165  m_lSelectedChannels = selectedChannels;
166  update();
167 }
168 
169 //=============================================================================================================
170 
172 {
173  update();
174 }
175 
176 //=============================================================================================================
177 
178 void ButterflyView::setBackgroundColor(const QColor& backgroundColor)
179 {
180  m_colCurrentBackgroundColor = backgroundColor;
181  update();
182 }
183 
184 //=============================================================================================================
185 
187 {
189 }
190 
191 //=============================================================================================================
192 
193 void 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 
217 QSharedPointer<QMap<QString, QColor> > ButterflyView::getAverageColor() const
218 {
219  return m_qMapAverageColor;
220 }
221 
222 //=============================================================================================================
223 
224 QSharedPointer<QMap<QString, bool> > ButterflyView::getAverageActivation() const
225 {
227 }
228 
229 //=============================================================================================================
230 
231 void ButterflyView::setAverageColor(const QSharedPointer<QMap<QString, QColor> > qMapAverageColor)
232 {
233  m_qMapAverageColor = qMapAverageColor;
234  update();
235 }
236 
237 //=============================================================================================================
238 
239 void ButterflyView::setSingleAverageColor(const QColor& avgColor)
240 {
241  for (QString mapKey : m_qMapAverageColor->keys())
242  m_qMapAverageColor->insert(mapKey, avgColor);
243 }
244 
245 //=============================================================================================================
246 
247 void ButterflyView::setAverageActivation(const QSharedPointer<QMap<QString, bool> > qMapAverageActivation)
248 {
249  m_qMapAverageActivation = qMapAverageActivation;
250  update();
251 }
252 
253 //=============================================================================================================
254 
255 void ButterflyView::setChannelInfoModel(QSharedPointer<ChannelInfoModel> &pChannelInfoModel)
256 {
257  m_pChannelInfoModel = pChannelInfoModel;
258 }
259 
260 //=============================================================================================================
261 
262 void ButterflyView::showSelectedChannelsOnly(const QStringList& selectedChannels)
263 {
264  if(!m_pChannelInfoModel) {
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 
279 void 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 
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 
504 void 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 
613 QSharedPointer<EvokedSetModel> ButterflyView::getEvokedSetModel()
614 {
615  return m_pEvokedSetModel;
616 }
617 
618 //=============================================================================================================
619 
621 {
622  setEvokedSetModel(Q_NULLPTR);
623 }
DISPSHARED_EXPORT float getScalingValue(const QMap< qint32, float > &qMapChScaling, int iChannelKind, int iChannelUnit)
void setSelectedChannels(const QList< int > &selectedChannels)
void setModalityMap(const QMap< QString, bool > &modalityMap)
void setEvokedSetModel(QSharedPointer< EvokedSetModel > model)
Declaration of the ScalingView Class.
The declaration for ChannelInfoModel..
void createPlotPath(qint32 row, QPainter &painter) const
QSharedPointer< EvokedSetModel > m_pEvokedSetModel
QMap< QString, bool > m_modalityMap
QMap< qint32, float > m_scaleMap
void setScaleMap(const QMap< qint32, float > &scaleMap)
void setSingleAverageColor(const QColor &avgColor)
void setAverageColor(const QSharedPointer< QMap< QString, QColor > > qMapAverageColor)
void takeScreenshot(const QString &fileName)
QSharedPointer< QMap< QString, QColor > > getAverageColor() const
void showSelectedChannels(const QList< int > selectedChannelsIndexes)
QMap< QString, bool > getModalityMap()
const QColor & getBackgroundColor()
QSharedPointer< EvokedSetModel > getEvokedSetModel()
ButterflyView(const QString &sSettingsPath="", QWidget *parent=0, Qt::WindowFlags f=Qt::Widget)
void showSelectedChannelsOnly(const QStringList &selectedChannels)
void setAverageActivation(const QSharedPointer< QMap< QString, bool > > qMapAverageActivation)
void setBackgroundColor(const QColor &backgroundColor)
QList< int > m_lSelectedChannels
QSharedPointer< QMap< QString, bool > > m_qMapAverageActivation
void setChannelInfoModel(QSharedPointer< ChannelInfoModel > &pChannelInfoModel)
Declaration of the EvokedSetModel Class.
Declaration of the ButterflyView class.
QSharedPointer< QMap< QString, QColor > > m_qMapAverageColor
QSharedPointer< ChannelInfoModel > m_pChannelInfoModel
QSharedPointer< QMap< QString, bool > > getAverageActivation() const