diff --git a/Histogram2D.h b/Histogram2D.h index 93f2a46..3d04030 100644 --- a/Histogram2D.h +++ b/Histogram2D.h @@ -19,173 +19,7 @@ const QList> colorCycle = { {QColor(Qt::red), "Red"}, class Histogram2D : public QCustomPlot{ public: - Histogram2D(QString title, QString xLabel, QString yLabel, int xbin, double xmin, double xmax, int ybin, double ymin, double ymax, QWidget * parent = nullptr) : QCustomPlot(parent){ - // DebugPrint("%s", "Histogram2D"); - for( int i = 0; i < 3; i ++ ){ - for( int j = 0; j < 3; j ++ ){ - box[i][j] = nullptr; - txt[i][j] = nullptr; - } - } - - isChannelMap = false; - tickStep = 1; // only used when isChannelMap = true - isLogZ = false; - - axisRect()->setupFullAxesBox(true); - xAxis->setLabel(xLabel); - yAxis->setLabel(yLabel); - - colorMap = new QCPColorMap(xAxis, yAxis); - Rebin(xbin, xmin, xmax, ybin, ymin, ymax); - colorMap->setInterpolate(false); - - QCPTextElement *titleEle = new QCPTextElement(this, title, QFont("sans", 12)); - plotLayout()->insertRow(0); - plotLayout()->addElement(0, 0, titleEle); - - colorScale = new QCPColorScale(this); - plotLayout()->addElement(1, 1, colorScale); - colorScale->setType(QCPAxis::atRight); - colorMap->setColorScale(colorScale); - - - QCPColorGradient color; - color.setNanHandling(QCPColorGradient::NanHandling::nhNanColor); - color.setNanColor(QColor("white")); - color.clearColorStops(); - // color.setColorStopAt( 0.0, QColor("white" )); - color.setColorStopAt( 0.0, QColor("purple" )); - color.setColorStopAt( 0.2, QColor("blue")); - color.setColorStopAt( 0.4, QColor("cyan")); - color.setColorStopAt( 0.6, QColor("green")); - color.setColorStopAt( 0.8, QColor("yellow")); - color.setColorStopAt( 1.0, QColor("red")); - colorMap->setGradient(color); - - double xPosStart = 0.02; - double xPosStep = 0.07; - double yPosStart = 0.02; - double yPosStep = 0.05; - - for( int i = 0; i < 3; i ++ ){ - for( int j = 0; j < 3; j ++ ){ - box[i][j] = new QCPItemRect(this); - - box[i][j]->topLeft->setType(QCPItemPosition::ptAxisRectRatio); - box[i][j]->topLeft->setCoords(xPosStart + xPosStep*i, yPosStart + yPosStep*j); - box[i][j]->bottomRight->setType(QCPItemPosition::ptAxisRectRatio); - box[i][j]->bottomRight->setCoords(xPosStart + xPosStep*(i+1), yPosStart + yPosStep*(j+1)); - - txt[i][j] = new QCPItemText(this); - txt[i][j]->setPositionAlignment(Qt::AlignLeft); - txt[i][j]->position->setType(QCPItemPosition::ptAxisRectRatio); - txt[i][j]->position->setCoords(xPosStart + xPosStep/2 + xPosStep*i, yPosStart + yPosStep*j);; - txt[i][j]->setText("0"); - txt[i][j]->setFont(QFont("Helvetica", 9)); - - } - } - - cutList.clear(); - cutEntryList.clear(); - - rescaleAxes(); - - usingMenu = false; - isDrawCut = false; - tempCutID = -1; - numCut = 0; - lastPlottableID = -1; - - line = new QCPItemLine(this); - line->setPen(QPen(Qt::gray, 1, Qt::DashLine)); - line->setVisible(false); - - isBusy = false; - - connect(this, &QCustomPlot::mouseMove, this, [=](QMouseEvent *event){ - double x = xAxis->pixelToCoord(event->pos().x()); - double y = yAxis->pixelToCoord(event->pos().y()); - int xI, yI; - colorMap->data()->coordToCell(x, y, &xI, &yI); - double z = colorMap->data()->cell(xI, yI); - - QString coordinates = QString("X: %1, Y: %2, Z: %3").arg(x).arg(y).arg(z); - QToolTip::showText(event->globalPosition().toPoint(), coordinates, this); - - //when drawing cut, show dashhed line - if( isDrawCut && tempCut.size() > 0 ){ - line->end->setCoords(x,y); - line->setVisible(true); - replot(); - } - - }); - - connect(this, &QCustomPlot::mousePress, this, [=](QMouseEvent * event){ - - if (event->button() == Qt::LeftButton && !usingMenu && !isDrawCut){ - setSelectionRectMode(QCP::SelectionRectMode::srmZoom); - } - - if (event->button() == Qt::LeftButton && isDrawCut){ - - oldMouseX = xAxis->pixelToCoord(event->pos().x()); - oldMouseY = yAxis->pixelToCoord(event->pos().y()); - - tempCut.push_back(QPointF(oldMouseX,oldMouseY)); - - line->start->setCoords(oldMouseX, oldMouseY); - line->end->setCoords(oldMouseX, oldMouseY); - line->setVisible(true); - - DrawCut(); - } - - //^================= right click - if (event->button() == Qt::RightButton) rightMouseClickMenu(event); - }); - - //connect( this, &QCustomPlot::mouseDoubleClick, this, [=](QMouseEvent *event){ - connect( this, &QCustomPlot::mouseDoubleClick, this, [=](){ - if( isDrawCut) { - tempCut.push_back(tempCut[0]); - DrawCut(); - isDrawCut = false; - line->setVisible(false); - - plottableIDList.push_back(plottableCount() -1 ); - - cutNameList.push_back("Cut-" + QString::number(cutList.count())); - cutEntryList.push_back(0); - - QCPItemText * text = new QCPItemText(this); - text->setText(cutNameList.last()); - text->position->setCoords(tempCut[0].rx(), tempCut[0].ry()); - int colorID = tempCutID% colorCycle.count(); - text->setColor(colorCycle[colorID].first); - cutTextIDList.push_back(itemCount() - 1); - - replot(); - - cutList.push_back(tempCut); - cutIDList.push_back(tempCutID); - - // qDebug() << "----------- end of create cut"; - // qDebug() << " cutIDList " << cutIDList ; - // qDebug() << "plottableIDList " << plottableIDList << ", " << plottableCount(); - // qDebug() << " cutTextIDList " << cutTextIDList << ", " << itemCount(); - - } - }); - - connect(this, &QCustomPlot::mouseRelease, this, [=](){ - - }); - } - - //^=================================== + Histogram2D(QString title, QString xLabel, QString yLabel, int xbin, double xmin, double xmax, int ybin, double ymin, double ymax, QWidget * parent = nullptr); void SetXTitle(QString xTitle) { xAxis->setLabel(xTitle);} void SetYTitle(QString yTitle) { yAxis->setLabel(yTitle);} @@ -194,25 +28,7 @@ public: void SetChannelMap(bool onOff, int tickStep = 1) { isChannelMap = onOff; this->tickStep = tickStep;} - void UpdatePlot(){ - // QCPColorGradient color; - // color.clearColorStops(); - // color.setNanColor(QColor("white")); - // // color.setColorStopAt( 0.0, QColor("white" )); - // // color.setColorStopAt( 1.0/entry[1][1], QColor("purple" )); - // color.setColorStopAt( 0.0, QColor("purple" )); - // color.setColorStopAt( 0.2, QColor("blue")); - // color.setColorStopAt( 0.4, QColor("cyan")); - // color.setColorStopAt( 0.6, QColor("green")); - // color.setColorStopAt( 0.8, QColor("yellow")); - // color.setColorStopAt( 1.0, QColor("red")); - // colorMap->setGradient(color); - - colorMap->rescaleDataRange(); - - replot(); - } - + void UpdatePlot(){ colorMap->rescaleDataRange(); replot(); } void Clear(); // Clear Data and histrogram void Fill(double x, double y); @@ -232,6 +48,9 @@ public: double GetYMin() const {return yMin;} double GetYMax() const {return yMax;} + void SaveCuts(QString cutFileName); + void LoadCuts(QString cutFileName); + private: double xMin, xMax, yMin, yMax; int xBin, yBin; @@ -252,15 +71,15 @@ private: QPolygonF tempCut; int tempCutID; // only incresing; - QList cutList; - QList cutIDList; int numCut; + QList cutList; + QList cutNameList; // name of the cut + QList cutEntryList; // number of entry inside the cut. + QList cutIDList; // ID of the cut + QList cutTextIDList; // + QList plottableIDList; bool isDrawCut; int lastPlottableID; - QList cutTextIDList; - QList plottableIDList; - QList cutNameList; - QList cutEntryList; QCPItemLine * line; double oldMouseX = 0.0, oldMouseY = 0.0; @@ -275,6 +94,174 @@ private: //^############################################### //^############################################### +inline Histogram2D::Histogram2D(QString title, QString xLabel, QString yLabel, int xbin, double xmin, double xmax, int ybin, double ymin, double ymax, QWidget * parent) : QCustomPlot(parent){ + // DebugPrint("%s", "Histogram2D"); + for( int i = 0; i < 3; i ++ ){ + for( int j = 0; j < 3; j ++ ){ + box[i][j] = nullptr; + txt[i][j] = nullptr; + } + } + + isChannelMap = false; + tickStep = 1; // only used when isChannelMap = true + isLogZ = false; + + axisRect()->setupFullAxesBox(true); + xAxis->setLabel(xLabel); + yAxis->setLabel(yLabel); + + colorMap = new QCPColorMap(xAxis, yAxis); + Rebin(xbin, xmin, xmax, ybin, ymin, ymax); + colorMap->setInterpolate(false); + + QCPTextElement *titleEle = new QCPTextElement(this, title, QFont("sans", 12)); + plotLayout()->insertRow(0); + plotLayout()->addElement(0, 0, titleEle); + + colorScale = new QCPColorScale(this); + plotLayout()->addElement(1, 1, colorScale); + colorScale->setType(QCPAxis::atRight); + colorMap->setColorScale(colorScale); + + + QCPColorGradient color; + color.setNanHandling(QCPColorGradient::NanHandling::nhNanColor); + color.setNanColor(QColor("white")); + color.clearColorStops(); + // color.setColorStopAt( 0.0, QColor("white" )); + color.setColorStopAt( 0.0, QColor("purple" )); + color.setColorStopAt( 0.2, QColor("blue")); + color.setColorStopAt( 0.4, QColor("cyan")); + color.setColorStopAt( 0.6, QColor("green")); + color.setColorStopAt( 0.8, QColor("yellow")); + color.setColorStopAt( 1.0, QColor("red")); + colorMap->setGradient(color); + + double xPosStart = 0.02; + double xPosStep = 0.07; + double yPosStart = 0.02; + double yPosStep = 0.05; + + for( int i = 0; i < 3; i ++ ){ + for( int j = 0; j < 3; j ++ ){ + box[i][j] = new QCPItemRect(this); + + box[i][j]->topLeft->setType(QCPItemPosition::ptAxisRectRatio); + box[i][j]->topLeft->setCoords(xPosStart + xPosStep*i, yPosStart + yPosStep*j); + box[i][j]->bottomRight->setType(QCPItemPosition::ptAxisRectRatio); + box[i][j]->bottomRight->setCoords(xPosStart + xPosStep*(i+1), yPosStart + yPosStep*(j+1)); + + txt[i][j] = new QCPItemText(this); + txt[i][j]->setPositionAlignment(Qt::AlignLeft); + txt[i][j]->position->setType(QCPItemPosition::ptAxisRectRatio); + txt[i][j]->position->setCoords(xPosStart + xPosStep/2 + xPosStep*i, yPosStart + yPosStep*j);; + txt[i][j]->setText("0"); + txt[i][j]->setFont(QFont("Helvetica", 9)); + + } + } + + cutList.clear(); + cutEntryList.clear(); + + rescaleAxes(); + + usingMenu = false; + isDrawCut = false; + tempCutID = -1; + numCut = 0; + lastPlottableID = -1; + + line = new QCPItemLine(this); + line->setPen(QPen(Qt::gray, 1, Qt::DashLine)); + line->setVisible(false); + + isBusy = false; + + connect(this, &QCustomPlot::mouseMove, this, [=](QMouseEvent *event){ + double x = xAxis->pixelToCoord(event->pos().x()); + double y = yAxis->pixelToCoord(event->pos().y()); + int xI, yI; + colorMap->data()->coordToCell(x, y, &xI, &yI); + double z = colorMap->data()->cell(xI, yI); + + QString coordinates = QString("X: %1, Y: %2, Z: %3").arg(x).arg(y).arg(z); + QToolTip::showText(event->globalPosition().toPoint(), coordinates, this); + + //when drawing cut, show dashhed line + if( isDrawCut && tempCut.size() > 0 ){ + line->end->setCoords(x,y); + line->setVisible(true); + replot(); + } + + }); + + connect(this, &QCustomPlot::mousePress, this, [=](QMouseEvent * event){ + + if (event->button() == Qt::LeftButton && !usingMenu && !isDrawCut){ + setSelectionRectMode(QCP::SelectionRectMode::srmZoom); + } + + if (event->button() == Qt::LeftButton && isDrawCut){ + + oldMouseX = xAxis->pixelToCoord(event->pos().x()); + oldMouseY = yAxis->pixelToCoord(event->pos().y()); + + tempCut.push_back(QPointF(oldMouseX,oldMouseY)); + + line->start->setCoords(oldMouseX, oldMouseY); + line->end->setCoords(oldMouseX, oldMouseY); + line->setVisible(true); + + DrawCut(); + } + + //^================= right click + if (event->button() == Qt::RightButton) rightMouseClickMenu(event); + }); + + //connect( this, &QCustomPlot::mouseDoubleClick, this, [=](QMouseEvent *event){ + connect( this, &QCustomPlot::mouseDoubleClick, this, [=](){ + if( isDrawCut) { + tempCut.push_back(tempCut[0]); + DrawCut(); + isDrawCut = false; + line->setVisible(false); + + plottableIDList.push_back(plottableCount() -1 ); + + cutNameList.push_back("Cut-" + QString::number(cutList.count())); + cutEntryList.push_back(0); + + QCPItemText * text = new QCPItemText(this); + text->setText(cutNameList.last()); + text->position->setCoords(tempCut[0].rx(), tempCut[0].ry()); + int colorID = tempCutID% colorCycle.count(); + text->setColor(colorCycle[colorID].first); + cutTextIDList.push_back(itemCount() - 1); + + replot(); + + cutList.push_back(tempCut); + cutIDList.push_back(tempCutID); + + // qDebug() << "----------- end of create cut"; + // qDebug() << " cutIDList " << cutIDList ; + // qDebug() << "plottableIDList " << plottableIDList << ", " << plottableCount(); + // qDebug() << " cutTextIDList " << cutTextIDList << ", " << itemCount(); + + } + }); + + connect(this, &QCustomPlot::mouseRelease, this, [=](){ + + }); +} + + + inline void Histogram2D::Fill(double x, double y){ // DebugPrint("%s", "Histogram2D"); if( isBusy ) return; @@ -391,7 +378,7 @@ inline void Histogram2D::ClearAllCuts(){ inline void Histogram2D::PrintCutEntry() const{ DebugPrint("%s", "Histogram2D"); if( numCut == 0 ) return; - printf("=============== There are %d cuts.\n", numCut); + printf("=============== There are %d cuts. (%lld, %lld)\n", numCut, cutList.count(), cutEntryList.count()); for( int i = 0; i < cutList.count(); i++){ if( cutList[i].isEmpty() ) continue; printf("%10s | %d \n", cutNameList[i].toStdString().c_str(), cutEntryList[i]); @@ -423,7 +410,7 @@ inline void Histogram2D::DrawCut(){ } replot(); - //qDebug() << "Plottable count : " << plottableCount() << ", cutList.count :" << cutList.count() << ", cutID :" << lastPlottableID; + // qDebug() << "Plottable count : " << plottableCount() << ", cutList.count :" << cutList.count() << ", cutID :" << lastPlottableID; } inline void Histogram2D::rightMouseClickMenu(QMouseEvent * event){ @@ -439,8 +426,11 @@ inline void Histogram2D::rightMouseClickMenu(QMouseEvent * event){ QAction * a2 = menu->addAction("Clear hist."); QAction * a3 = menu->addAction("Toggle Stat."); QAction * a4 = menu->addAction("Rebin (clear histogram)"); + QAction * a8 = menu->addAction("Load Cut(s)"); QAction * a5 = menu->addAction("Create a Cut"); + QAction * a7 = nullptr; if( numCut > 0 ) { + a7 = menu->addAction("Save Cut(s)"); menu->addSeparator(); menu->addAction("Add/Edit names to Cuts"); menu->addAction("Clear all Cuts"); @@ -575,6 +565,27 @@ inline void Histogram2D::rightMouseClickMenu(QMouseEvent * event){ return; } + if( selectedAction == a8 ){ // load Cuts + QString filePath = QFileDialog::getOpenFileName(this, + "Load Cuts from File", + QDir::homePath(), + "Text file (*.txt)"); + + if (!filePath.isEmpty()) LoadCuts(filePath); + + } + + if( selectedAction == a7 ){ // Save Cuts + + QString filePath = QFileDialog::getSaveFileName(this, + "Save Cuts to File", + QDir::homePath(), + "Text file (*.txt)"); + + if (!filePath.isEmpty()) SaveCuts(filePath); + + } + } @@ -674,5 +685,113 @@ inline void Histogram2D::rightMouseClickRebin(){ } +inline void Histogram2D::SaveCuts(QString cutFileName){ + + QFile file(cutFileName); + if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { + QTextStream out(&file); + + // Define the text to write + QStringList lines; + + for( int i = 0; i < cutList.size(); i++){ + lines << "====== "+ cutNameList[i]; + for( int pt = 0 ; pt < cutList[i].size(); pt ++){ + lines << QString::number(cutList[i][pt].rx(), 'g', 5) + "," + QString::number(cutList[i][pt].ry(), 'g', 5); + } + } + + lines << "#===== End of File"; + + // Write each line to the file + for (const QString &line : lines) out << line << "\n"; + + // Close the file + file.close(); + qDebug() << "File written successfully to" << cutFileName; + }else{ + qWarning() << "Unable to open file" << cutFileName; + } + +} + +inline void Histogram2D::LoadCuts(QString cutFileName){ + + QFile file(cutFileName); + QString cutNameTemp; + + // Open the file in read mode + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QTextStream in(&file); + + ClearAllCuts(); + tempCut.clear(); + + // Read each line and append to the QStringList + + while (!in.atEnd()) { + QString line = in.readLine(); + + if( line.contains("======") ){ + if( !tempCut.isEmpty() ) { + DrawCut(); + plottableIDList.push_back(plottableCount() -1 ); + cutNameList.push_back(cutNameTemp); + cutEntryList.push_back(0); + QCPItemText * text = new QCPItemText(this); + text->setText(cutNameList.last()); + text->position->setCoords(tempCut[0].rx(), tempCut[0].ry()); + int colorID = tempCutID% colorCycle.count(); + text->setColor(colorCycle[colorID].first); + cutTextIDList.push_back(itemCount() - 1); + // cutList.push_back(tempCut); + cutIDList.push_back(tempCutID); + } + tempCut.clear(); + tempCutID ++; + numCut ++; + + int spacePos = line.indexOf(' '); + cutNameTemp = line.mid(spacePos + 1); + continue; + } + + if( line.contains("#==") ) { + DrawCut(); + plottableIDList.push_back(plottableCount() -1 ); + cutNameList.push_back(cutNameTemp); + cutEntryList.push_back(0); + QCPItemText * text = new QCPItemText(this); + text->setText(cutNameList.last()); + text->position->setCoords(tempCut[0].rx(), tempCut[0].ry()); + int colorID = tempCutID% colorCycle.count(); + text->setColor(colorCycle[colorID].first); + cutTextIDList.push_back(itemCount() - 1); + cutList.push_back(tempCut); + cutIDList.push_back(tempCutID); + break; + }else{ + QStringList haha = line.split(","); + // qDebug() << haha; + tempCut.push_back(QPointF(haha[0].toFloat(), haha[1].toFloat())); + DrawCut(); + } + + } + + // Close the file + file.close(); + qDebug() << "File read successfully from" << cutFileName; + + // PrintCutEntry(); + // DrawCut(); + replot(); + + } else { + qWarning() << "Unable to open file" << cutFileName; + } + +} + #endif \ No newline at end of file