SpikeStream Application Library  0.2
SpikeRasterWidget.cpp
Go to the documentation of this file.
00001 //SpikeStream includes
00002 #include "Globals.h"
00003 #include "SpikeRasterWidget.h"
00004 #include "SpikeStreamException.h"
00005 using namespace spikestream;
00006 
00007 //Qt includes
00008 #include <QFileDialog>
00009 #include <QMessageBox>
00010 #include <QPainter>
00011 #include <QResizeEvent>
00012 #include <QDebug>
00013 
00014 
00016 SpikeRasterWidget::SpikeRasterWidget(QList<NeuronGroup*>& neuronGroupList, QWidget* parent) : QWidget(parent){
00017         //Store list of neuron groups that are being monitored
00018         this->neuronGroupList = neuronGroupList;
00019 
00020         //Calculate number of neurons along with their offset and colour
00021         QList<unsigned> hueList = getHueList(neuronGroupList.size());
00022         numNeurons = 0;
00023         int hueCntr = 0;
00024         for(QList<NeuronGroup*>::iterator iter = neuronGroupList.begin(); iter != neuronGroupList.end(); ++iter){
00025                 neurGrpOffsetMap[(*iter)->getID()] = numNeurons;
00026                 neurGrpColorMap[(*iter)->getID()] = hueList.at(hueCntr);
00027                 ++hueCntr;
00028                 numNeurons += (*iter)->size();
00029         }
00030 
00031         //Initialize display variables
00032         blackAndWhiteMode = false;
00033         xAxisTickLength = 2;
00034         yAxisTickLength = 2;
00035         fontSize = 10;
00036         neurGrpNameFontSize = 10;
00037         yAxisPadding = yAxisTickLength + 1 + fontSize * QString::number(numNeurons).length();
00038         xAxisPadding = xAxisTickLength + 1 + fontSize;
00039         backgroundColor = qRgb(255,255,255);
00040         axesColor = qRgb(0,0,0);
00041 
00042         //Initialize other variables
00043         numTimeSteps = 1000;
00044         minTimeStep = 0;
00045 
00046         //Create buffer image
00047         imageWidth = numTimeSteps + yAxisPadding + 1;
00048         imageHeight = numNeurons + xAxisPadding + 1;
00049         bufferImage = new QImage(imageWidth, imageHeight, QImage::Format_RGB32);
00050         bufferImage->fill(backgroundColor);
00051         updateAxes = true;
00052 
00053         //Set up widget graphic properties
00054         if(imageWidth > 500)
00055                 setMinimumWidth(500);
00056         else
00057                 setMinimumWidth(imageWidth);
00058         if(imageHeight > 500)
00059                 setMinimumHeight(500);
00060         else
00061                 setMinimumHeight(imageHeight);
00062         //setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
00063         setAttribute(Qt::WA_OpaquePaintEvent);
00064         setAttribute(Qt::WA_PaintOnScreen);
00065         widgetWidth = this->size().width();
00066         widgetHeight = this->size().height();
00067 }
00068 
00069 
00071 SpikeRasterWidget::~SpikeRasterWidget(){
00072         delete bufferImage;
00073 }
00074 
00075 
00076 /*----------------------------------------------------------*/
00077 /*------               PUBLIC METHODS                 ------*/
00078 /*----------------------------------------------------------*/
00079 
00081 void SpikeRasterWidget::addSpikes(const QList<unsigned>& firingNeuronIDs, int timeStep){
00082         int writeLocation = timeStep % numTimeSteps +  yAxisPadding + 1;
00083 
00084         //Add spikes to the current image
00085         unsigned tmpNeurID;
00086         QList<unsigned>::const_iterator firingNeuronIDsEnd = firingNeuronIDs.end();
00087         for(QList<unsigned>::const_iterator neurIter = firingNeuronIDs.begin(); neurIter != firingNeuronIDsEnd; ++neurIter){
00088                 for(QList<NeuronGroup*>::iterator neurGrpIter = neuronGroupList.begin(); neurGrpIter != neuronGroupList.end(); ++neurGrpIter){
00089                         if((*neurGrpIter)->contains(*neurIter)){
00090                                 tmpNeurID = *neurIter - (*neurGrpIter)->getStartNeuronID() + neurGrpOffsetMap[(*neurGrpIter)->getID()];
00091                                 bufferImage->setPixel(writeLocation, imageHeight - xAxisPadding - tmpNeurID - 1, neurGrpColorMap[(*neurGrpIter)->getID()]);
00092                                 break;
00093                         }
00094                 }
00095         }
00096 
00097         //Advance the time step
00098         increaseTimeStep(timeStep);
00099         repaint();
00100 }
00101 
00102 
00104 void SpikeRasterWidget::setBlackAndWhite(bool on){
00105         blackAndWhiteMode = on;
00106 
00107         //Reload hues
00108         QList<unsigned> hueList = getHueList(neuronGroupList.size());
00109         int hueCntr = 0;
00110         for(QList<NeuronGroup*>::iterator iter = neuronGroupList.begin(); iter != neuronGroupList.end(); ++iter){
00111                 neurGrpColorMap[(*iter)->getID()] = hueList.at(hueCntr);
00112                 ++hueCntr;
00113         }
00114         repaint();
00115 }
00116 
00117 
00118 /*----------------------------------------------------------*/
00119 /*------              PROTECTED METHODS               ------*/
00120 /*----------------------------------------------------------*/
00121 
00123 void SpikeRasterWidget::mouseDoubleClickEvent (QMouseEvent*){
00124         QString fileType = "BMP";
00125         QString filePath = getFilePath("*." + fileType.toLower());
00126 
00127         //Fix extension
00128         if(!filePath.endsWith(fileType.toLower()))
00129                 filePath += "." + fileType.toLower();
00130 
00131         //If file exists, check to see if user wants to overwrite file
00132         if(QFile::exists(filePath)){
00133                 int response = QMessageBox::warning(this, "Overwrite File?", filePath + " already exists.\nAre you sure that you want to overwrite it?", QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Cancel);
00134                 if(response != QMessageBox::Ok)
00135                         return;
00136         }
00137 
00138         //Save file
00139         bufferImage->save(filePath, fileType.toAscii(), 100);
00140 }
00141 
00142 
00143 //Inherited from QWidget
00144 void SpikeRasterWidget::paintEvent(QPaintEvent*){
00145         QPainter painter(this);
00146         if(updateAxes){
00147                 QPainter axesPainter(bufferImage);
00148                 paintAxes(axesPainter);
00149                 paintNeuronGroupNames(axesPainter);
00150         }
00151 
00152         painter.drawImage(0, 0, bufferImage->scaled(widgetWidth, widgetHeight));
00153         painter.end();
00154 }
00155 
00156 
00157 //Inherited from QWidget
00158 void SpikeRasterWidget::resizeEvent(QResizeEvent* /*event*/) {
00159         widgetWidth = this->size().width();
00160         widgetHeight = this->size().height();
00161 }
00162 
00163 
00164 /*----------------------------------------------------------*/
00165 /*------              PRIVATE METHODS                 ------*/
00166 /*----------------------------------------------------------*/
00167 
00169 QString SpikeRasterWidget::getFilePath(QString fileFilter){
00170         QFileDialog dialog(this);
00171         dialog.setDirectory(Globals::getWorkingDirectory());
00172         dialog.setFileMode(QFileDialog::AnyFile);
00173         dialog.setNameFilter( QString("Image file (" + fileFilter + ")") );
00174         dialog.setWindowTitle("Save");
00175         dialog.setViewMode(QFileDialog::Detail);
00176         QStringList fileNames;
00177         if (dialog.exec())
00178                 fileNames = dialog.selectedFiles();
00179         if(fileNames.size() > 0)
00180                 return fileNames[0];
00181         else
00182                 return QString("");
00183 }
00184 
00185 
00187 QList<unsigned> SpikeRasterWidget::getHueList(unsigned numItems){
00188         QList<unsigned> tmpHueList;
00189 
00190         //Return black spike colour in black and white mode
00191         if(blackAndWhiteMode){
00192                 for(unsigned i=0; i<numItems; ++i)
00193                         tmpHueList.append(qRgb(0, 0, 0));
00194                 return tmpHueList;
00195         }
00196 
00197         //Colour mode
00198         unsigned numHues = 1530;
00199 
00200         //Sanity check
00201         if(numItems > numHues)
00202                 throw SpikeStreamException("Number of requested hues exceeds that available.");
00203 
00204         //Prevent divide by zero
00205         if(numItems == 0)
00206                 return tmpHueList;
00207         else if(numItems == 1){
00208                 tmpHueList.append(qRgb(255, 0, 0));
00209                 return tmpHueList;
00210         }
00211 
00212         for(unsigned i=0; i <= numHues - numHues%(numItems-1); i += numHues/(numItems-1)){
00213                 if(i < 255)
00214                         tmpHueList.append(qRgb(255, i, 0));
00215                 else if (i < 510)
00216                         tmpHueList.append(qRgb(i-255, 255, 0));
00217                 else if (i < 765)
00218                         tmpHueList.append(qRgb(0, 255, i - 510));
00219                 else if (i < 1020)
00220                         tmpHueList.append(qRgb(0, i-765, 255));
00221                 else if (i < 1275)
00222                         tmpHueList.append(qRgb(i-1020, 0, 255));
00223                 else
00224                         tmpHueList.append(qRgb(255, 0, i-1275));
00225         }
00226 
00227         if((int)numItems != tmpHueList.size())
00228                 throw SpikeStreamException("Incorrect number of hues found. NumItems: " + QString::number(numItems) + "; size: " + QString::number(tmpHueList.size()));
00229 
00230         return tmpHueList;
00231 }
00232 
00233 
00235 void SpikeRasterWidget::increaseTimeStep(int currentTimeStep){
00236         //Check to see if we have moved out of the X axis range
00237         if( ((currentTimeStep /numTimeSteps) * numTimeSteps) != minTimeStep){
00238                 minTimeStep = (currentTimeStep/numTimeSteps) * numTimeSteps;
00239                 bufferImage->fill(backgroundColor);
00240                 updateAxes = true;
00241         }
00242 }
00243 
00244 
00246 void SpikeRasterWidget::paintAxes(QPainter& painter) {
00247         painter.setPen( QPen(Qt::black) );
00248 
00249         //Set up font
00250         QFont font;
00251         font.setFamily("Helvetica");
00252         font.setWeight(QFont::Light);
00253         font.setPixelSize(fontSize);
00254         painter.setFont(font);
00255 
00256         //Paint axes
00257         paintYAxis(painter);
00258         paintXAxis(painter);
00259 
00260         //Set flag recording that axes are updated
00261         updateAxes = false;
00262 }
00263 
00264 
00266 void SpikeRasterWidget::paintNeuronGroupNames(QPainter& painter){
00267         //Set up font
00268         QFont font;
00269         font.setFamily("Helvetica");
00270         font.setWeight(QFont::Light);
00271         font.setPixelSize(neurGrpNameFontSize);
00272         painter.setFont(font);
00273 
00274         for(QList<NeuronGroup*>::iterator neurGrpIter = neuronGroupList.begin(); neurGrpIter != neuronGroupList.end(); ++neurGrpIter){
00275                 painter.setPen( QPen( QColor(neurGrpColorMap[(*neurGrpIter)->getID()]) ) );
00276                 painter.drawText(
00277                                 imageWidth/2, imageHeight - xAxisPadding - neurGrpOffsetMap[(*neurGrpIter)->getID()],
00278                                 (*neurGrpIter)->getInfo().getName()
00279                 );
00280         }
00281 }
00282 
00283 
00285 void SpikeRasterWidget::paintXAxis(QPainter& painter) {
00286         //Draw X axis line
00287         painter.drawLine(0, imageHeight-xAxisPadding, imageWidth, imageHeight-xAxisPadding);
00288 
00289         //Draw ticks
00290         for(int i=0; i<numTimeSteps; i += numTimeSteps/10)
00291                 paintXAxisTick(painter, i + yAxisPadding, minTimeStep + i);
00292 }
00293 
00294 
00296 void SpikeRasterWidget::paintXAxisTick(QPainter& painter, int xPos, int labelX) {
00297         painter.drawLine(xPos,
00298                                          imageHeight - xAxisPadding,
00299                                          xPos,
00300                                          imageHeight-xAxisPadding + xAxisTickLength
00301         );
00302         int textW = fontSize*5;
00303         painter.drawText(
00304                         xPos - textW/2, imageHeight-xAxisPadding + xAxisTickLength,
00305                         textW, fontSize,
00306                         Qt::AlignHCenter,
00307                         QString::number(labelX) + "ms"
00308         );
00309 }
00310 
00311 
00313 void SpikeRasterWidget::paintYAxisTick(QPainter& painter, int yPos, int label) {
00314         painter.drawLine(yAxisPadding, yPos, yAxisPadding - yAxisTickLength, yPos);
00315         painter.drawText(
00316                         0, yPos + fontSize/2,
00317                         QString::number(label)
00318         );
00319 }
00320 
00321 
00323 void SpikeRasterWidget::paintYAxis(QPainter& painter){
00324         //Draw Y axis line
00325         painter.drawLine(yAxisPadding, 0, yAxisPadding, imageHeight);
00326 
00327         //Draw ticks
00328         for(int i=0; i<numNeurons; i += numNeurons/10){
00329                 paintYAxisTick(painter, imageHeight - xAxisPadding - i, i);
00330         }
00331 }
00332 
00333 
 All Classes Files Functions Variables Typedefs Friends Defines