#include #include #include #include #include #include #include "centralwidget.h" #include "filemanager.h" #include "pointcalculate.h" #include "logger.h" #include "xlsxhandler.h" CentralWidget::CentralWidget(QWidget *parent) : QWidget(parent) ,_customPlot(new LocalCustomPlot(this)) // ,_customPlot(new QCustomPlot(this)) ,_analysisMode(AnalysisMode::Null) ,_currentCurve(nullptr) ,_axisMode(AxisMode::SingleY) { setMouseTracking(true); setStyleSheet("background-color: lightgray;"); resize(888, 666); QHBoxLayout *layout = new QHBoxLayout(); layout->setMargin(0); layout->addWidget(_customPlot); this->setLayout(layout); // 创建两条竖线 _line1 = new QCPItemStraightLine(_customPlot); _line1->point1->setCoords(20, _customPlot->yAxis->range().lower); _line1->point2->setCoords(20, _customPlot->yAxis->range().upper); _line1->setPen(QPen(Qt::red)); _line1->setSelectable(true); _line2 = new QCPItemStraightLine(_customPlot); _line2->point1->setCoords(40, _customPlot->yAxis->range().lower); _line2->point2->setCoords(40, _customPlot->yAxis->range().upper); _line2->setPen(QPen(Qt::red)); _line2->setSelectable(true); // 安装事件过滤器 // _graph = _customPlot->addGraph(0); // _eventHandler = new EventHandler(_customPlot, _line1, _line2, _graph, nullptr); _eventHandler = new EventHandler(_customPlot, _line1, _line2, nullptr); _eventHandler->setEnable(true); _customPlot->installEventFilter(_eventHandler); _customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables); // _customPlot->setInteractions( QCP::iRangeZoom | QCP::iSelectPlottables); // _customPlot->setInteractions(QCP::iSelectPlottables); connect(_eventHandler,&EventHandler::sigSendLineXCoord, this,&CentralWidget::sigSendLineXCoord); setEventHandlerEnable(false); // #if 0 // init data QVector x(101), y(101); for (int i = 0; i < 101; i++) { x[i] = i / 50.0 - 1;//设置x的范围为-1~1 y[i] = x[i] * x[i]; } _customPlot->graph(0)->setData(x, y); //设置坐标轴标签 _customPlot->xAxis->setLabel("x coordinates"); _customPlot->yAxis->setLabel("y coordinates"); //设置坐标轴范围,以便我们可以看到全部数据 _customPlot->xAxis->setRange(0, 1); _customPlot->yAxis->setRange(0, 100); _customPlot->replot(); #endif // 设置坐标轴标签 _customPlot->xAxis->setLabel("Temp/℃"); _customPlot->yAxis->setLabel("DSC/mW"); // 设置坐标轴范围,以便我们可以看到全部数据 _customPlot->xAxis->setRange(0,100); _customPlot->yAxis->setRange(0,20); // startTimer(300); } CentralWidget::~CentralWidget() { } void CentralWidget::switchAxisMode() { if(Global::_mode != Global::Mode::Analysis){ return; } if(_axisMode == AxisMode::SingleY){ _axisMode = AxisMode::DoubleY; _customPlot->yAxis2->setVisible(true); _customPlot->yAxis2->setLabel("Time/min"); for(Global::CurveFileData& cfd:Global::_curveFileDataVtr){ for(Global::PhaseTotalInfo& pti:cfd.phaseTotalVtr){ QVector dataVtr; QVector tVtr,xVtr, yVtr; int index = 0; for (Global::ExperimentData &ed : pti.dataVtr) { tVtr.push_back(index++); xVtr.push_back(ed.sampleTemp); yVtr.push_back(ed.runTime); } double yMin = yVtr.first(); double yMax = yVtr.last(); double tick = (yMax - yMin) / 4; double axisMin = yMin - tick; double axisMax = yMax + tick; _customPlot->yAxis2->setRange(axisMin,axisMax); QCPCurve* curve = new QCPCurve(_customPlot->xAxis, _customPlot->yAxis2); curve->setData(tVtr, xVtr, yVtr); curve->setPen(QPen(QColor(Qt::red))); curve->setObjectName(Global::CurveOfTimeTypeObjectName); // logde<<"plottableCount count:"<<_customPlot->plottableCount(); } } }else{ _axisMode = AxisMode::SingleY; _customPlot->yAxis2->setVisible(false); // logde<<"graph count:"<<_customPlot->plottableCount(); for (int i = _customPlot->plottableCount() - 1; i >= 0; --i) { QCPAbstractPlottable* plottable = _customPlot->plottable(i); if (auto curve = dynamic_cast(plottable)) { if(curve && curve->objectName() == Global::CurveOfTimeTypeObjectName){ _customPlot->removePlottable(curve); } } } } _customPlot->replot(); } void CentralWidget::setAnalysisMode(const CentralWidget::AnalysisMode mode) { _analysisMode = mode; switch (mode) { case AnalysisMode::Null: _customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables); break; case AnalysisMode::NumericalLabel: case AnalysisMode::StartPoint: case AnalysisMode::StopPoint: case AnalysisMode::PeakSynthesisAnalysis: case AnalysisMode::GlassTransition: _customPlot->setInteractions(QCP::iSelectPlottables); setEventHandlerEnable(true); break; default: break; } } void CentralWidget::slotModeModify(const Global::Mode mode) { if (Global::Mode::Experiment == mode) { #if 0 if (_customPlot->graphCount() > 0 && _currentGraph) { // 清除第一个图表上的数据 _currentGraph->setData(QVector(), QVector()); } #endif // 创建画布,设置画布上的点数据 // _graph = _customPlot->addGraph(); // 设置坐标轴标签 _customPlot->xAxis->setLabel("Temp/℃"); _customPlot->yAxis->setLabel("DSC/mW"); // 设置坐标轴范围,以便我们可以看到全部数据 _customPlot->xAxis->setRange(0, 400); _customPlot->yAxis->setRange(-20, 20); } else if (Global::Mode::Analysis == mode) { qDebug() << "file close..."; } } void CentralWidget::slotRecvCommonData(const CommonData &cd) { // logde<<"slotRecvCommonData..."; static double index = 0.0; if(!_currentCurve){ logde<<"_currentCurve is nullptr"; _currentCurve = new QCPCurve(_customPlot->xAxis, _customPlot->yAxis); } // logde<<"temp:"<addData(index++,cd.sample_temp, cd.dsc); // _customPlot->rescaleAxes(); _customPlot->replot(); // return; // Record data. if(!Global::_currentCurveExperimentDataPtr){ loger<<"_currentCurveExperimentDataPtr is nullptr."; exit(0); }else{ Global::ExperimentData ed; ed.dsc = cd .dsc; ed.sampleTemp = cd.sample_temp; ed.runTime = cd.add_run_time; ed.constantTempTime = cd.add_constan_temp_time; Global::_currentCurveExperimentDataPtr->dataVtr.push_back(ed); Global::_currentCurveExperimentDataPtr->curve = _currentCurve; } } void CentralWidget::slotRecvAnalysisFileName(const QString &filePath) { if(_analysisFilePathVtr.contains(filePath)){ return; } qDebug() << "slotRecvAnalysisFileName" << filePath; Global::CurveFileData cfd; if(XlsxHandler::readFile(filePath,cfd) != 0){ QMessageBox::warning((QWidget*)this->parent(), "warnning", "File parse error."); return; } QFileInfo fileInfo(filePath); cfd.fileName = fileInfo.fileName(); for(int i = 0;i < cfd.phaseTotalVtr.size();i++){ Global::PhaseTotalInfo& pti = cfd.phaseTotalVtr[i]; logde<<"data Vtr size:"<startEndPointPair = PointCalculate::getStartAndEndPoint(); QPointF endPoint = startEndPointPair.second; _customPlot->xAxis->setRange(0, endPoint.x() / 3 * 4); //QPointF peakPoint = PointCalculate::getPeakPoint(); QPair maxMinPair = PointCalculate::getMaxMinValue(); float absY = std::abs(maxMinPair.first - maxMinPair.second); _customPlot->yAxis->setRange(- absY * 2,absY *2); _customPlot->yAxis->setLabel("DSC/mW"); _customPlot->xAxis->setLabel("Temp/℃"); QVector dataVtr; QVector tVtr,xVtr, yVtr; int index = 0; for (Global::ExperimentData &ed : pti.dataVtr) { tVtr.push_back(index++); xVtr.push_back(ed.sampleTemp); yVtr.push_back(ed.dsc); } _currentCurve = new QCPCurve(_customPlot->xAxis, _customPlot->yAxis); _currentCurve->setData(tVtr, xVtr, yVtr); _currentCurve->setSelectable(QCP::stWhole); // 设置曲线可选 pti.curve = _currentCurve; } // Add data to global parameter. Global::_curveFileDataVtr.push_back(cfd); _customPlot->rescaleAxes(); _customPlot->replot(); } void CentralWidget::slotAnalysisSettingApply() { switch (_analysisMode) { case AnalysisMode::NumericalLabel: { QPointF selectPoint = PointCalculate::getClosestPointByX( _line1->point1->coords().x()); logde<<"lin1 x:"<<_line1->point1->coords().x(); if(selectPoint.isNull()){ QMessageBox::warning((QWidget*)this->parent(), "warnning", "曲线选择错误."); return; } drawText(selectPoint, PointCalculate::textFormatNumbericalLabel(selectPoint)); break; } case AnalysisMode::StartPoint: case AnalysisMode::StopPoint:{ double x1 = _line1->point1->coords().x(); double x2 = _line2->point1->coords().x(); PointCalculate::setRegionPointX(x1,x2); QPair startEndPointPair = PointCalculate::calculateStartAndEndPoint(); if(_analysisMode == AnalysisMode::StartPoint){ drawText(startEndPointPair.first, PointCalculate::textFormatStartPoint(startEndPointPair.first)); }else{ drawText(startEndPointPair.second, PointCalculate::textFormatEndPoint(startEndPointPair.second)); } break; } case AnalysisMode::PeakSynthesisAnalysis: { double x1 = _line1->point1->coords().x(); double x2 = _line2->point1->coords().x(); fillGraph(x1,x2); PointCalculate::setRegionPointX(x1,x2); //enthalpy double sampleWeight = 0.0f; for(Global::CurveFileData& cfd:Global::_curveFileDataVtr){ for(Global::PhaseTotalInfo& pti:cfd.phaseTotalVtr){ if(_currentCurve && _currentCurve == pti.curve){ sampleWeight = cfd.ei.sampleWeight.toDouble(); } } } logde<<"sample weight:"< startEndPointPair = PointCalculate::calculateStartAndEndPoint(); logde<<"start,end:"<setVisible(false); _line2->setVisible(false); emit sigRightDockWidgetHide(); } void CentralWidget::slotAnalysisSettingUndo() { clearData(ClearDataMode::Undo); } void CentralWidget::slotAnalysisSettingCancel() { clearData(ClearDataMode::Undo); setAnalysisMode(CentralWidget::AnalysisMode::Null); _line1->setVisible(false); _line2->setVisible(false); emit sigRightDockWidgetHide(); } void CentralWidget::slotAnalysisSettingLineXPoint(const int index, const double) { } void CentralWidget::slotDrawCustomText(const QString str) { QCPItemText* customLegendItem = new QCPItemText(_customPlot); customLegendItem->position->setTypeX(QCPItemPosition::ptAbsolute); customLegendItem->position->setTypeY(QCPItemPosition::ptAbsolute); customLegendItem->position->setCoords(150, 50); // 稍微向下移动 customLegendItem->setText(str); QFont font("Arial", 10); customLegendItem->setFont(font); // 设置边框和背景 customLegendItem->setPen(QPen(Qt::black)); customLegendItem->setBrush(QBrush(Qt::white)); // 禁止点选 customLegendItem->setSelectable(false); customLegendItem->setObjectName("fixed"); _customPlot->replot(); } void CentralWidget::slotGetAxisInfo() { QVector vtr; auto func = [&](QCPAxis* axis){ AxisInfo ai; ai.visiable = axis->visible(); ai.lower = axis->range().lower; ai.upper = axis->range().upper; vtr.push_back(ai); }; func(_customPlot->xAxis); func(_customPlot->yAxis); func(_customPlot->yAxis2); emit sigGetAxisInfoWithData(vtr); } void CentralWidget::slotSetAxisSettings(const QVectorvtr) { _customPlot->xAxis->setRange(vtr.at(0),vtr.at(1)); _customPlot->yAxis->setRange(vtr.at(2),vtr.at(3)); if(_customPlot->yAxis2->visible()){ _customPlot->yAxis2->setRange(vtr.at(4),vtr.at(5)); } _customPlot->replot(); } void CentralWidget::timerEvent(QTimerEvent *event) { _customPlot->replot(); #if 0 // key的单位是秒 double key = QDateTime::currentDateTime().toMSecsSinceEpoch() / 1000.0; // 添加数据 // 使用随机数产生一条曲线 // double value0 = realDataI(); double value0 = QRandomGenerator::global()->bounded(10.123); _customPlot->graph(0)->addData(key, value0); // 添加数据到曲线 // 删除8秒之前的数据。这里的8要和下面设置横坐标宽度的8配合起来 // 才能起到想要的效果,可以调整这两个值,观察显示的效果。 _customPlot->graph(0)->data()->remove(key - 80); // 自动设定graph(1)曲线y轴的范围,如果不设定,有可能看不到图像 // 也可以用ui->customPlot->yAxis->setRange(up,low)手动设定y轴范围 _customPlot->graph(0)->rescaleValueAxis(true); // 这里的8,是指横坐标时间宽度为8秒,如果想要横坐标显示更多的时间 // 就把8调整为比较大到值,比如要显示60秒,那就改成60。 // 这时removeDataBefore(key-8)中的8也要改成60,否则曲线显示不完整。 _customPlot->yAxis->setRange(0, 20); // 设定x轴的范围 _customPlot->xAxis->setRange(key + 0.25, 80, Qt::AlignRight); // 设定x轴的范围 _customPlot->replot(); #endif } void CentralWidget::contextMenuEvent(QContextMenuEvent *event) { qDebug()<<"left menu..."; QPoint point = event->globalPos(); emit sigContextMenuShow(point); } void CentralWidget::glassTransitionHandle() { QPointF point1 = PointCalculate::getClosestPointByX(_line1->point1->coords().x()); QPointF point2 = PointCalculate::getClosestPointByX(_line2->point1->coords().x()); logde<<"point1:"<point1->setCoords(point1.x() - 5,point1.y()); line1->point2->setCoords(point1.x() + 5,point1.y()); line1->setPen(QPen(Qt::darkRed)); line1->setSelectable(false); line1->setVisible(true); QCPItemStraightLine *line2 = new QCPItemStraightLine(_customPlot); line2->point1->setCoords(point2.x() - 5,point2.y()); line2->point2->setCoords(point2.x() + 5,point2.y()); line2->setPen(QPen(Qt::darkGreen)); line2->setSelectable(false); line2->setVisible(true); _customPlot->replot(); #endif // PointCalculate::Line lineStrc1,lineStrc2,tangetLineStrc; lineStrc1.slope = 0.0; lineStrc1.intercept = point1.y(); lineStrc2.slope = 0.0; lineStrc2.intercept = point2.y(); QPair tangentLinePair = PointCalculate::getCurveInflectionPointTangent(point1.x(),point2.x()); tangetLineStrc.slope = tangentLinePair.first; tangetLineStrc.intercept = tangentLinePair.second; QPointF intersection1 = PointCalculate::getIntersection(tangetLineStrc,lineStrc1); QPointF intersection2 = PointCalculate::getIntersection(tangetLineStrc,lineStrc2); // logde<<"intersection1 x:"< xVtr,yVtr; xVtr.push_back(intersection1.x()); xVtr.push_back(point1.x()); yVtr.push_back(intersection1.y()); yVtr.push_back(point1.y()); QCPGraph *lineGraph1 = _customPlot->addGraph(); lineGraph1->setData(xVtr, yVtr); _customPlot->replot(); ///line2 QVector xVtr2,yVtr2; xVtr2.push_back(intersection2.x()); xVtr2.push_back(point2.x()); yVtr2.push_back(intersection2.y()); yVtr2.push_back(point2.y()); QCPGraph *lineGraph2 = _customPlot->addGraph(); lineGraph2->setData(xVtr2, yVtr2); _customPlot->replot(); //draw text drawText(averagePoint,str); _customPlot->replot(); #if 0 // 创建一个圆形绘图项 QCPItemEllipse *circle = new QCPItemEllipse(_customPlot); // _customPlot->addItem(circle); // 设置圆形的位置和大小 circle->topLeft->setCoords(-5, 5); circle->bottomRight->setCoords(5, -5); // 设置圆形的填充和边框颜色 circle->setBrush(QBrush(Qt::cyan)); circle->setPen(QPen(Qt::blue)); #endif #if 0 QCPItemStraightLine *line3 = new QCPItemStraightLine(_customPlot); line3->point1->setCoords(averagePoint.x() + 1,averagePoint.y() + 1); line3->point2->setCoords(averagePoint.x() - 1,averagePoint.y() - 1); line3->setPen(QPen(Qt::black)); line3->setSelectable(false); line3->setVisible(true); _customPlot->replot(); #endif } void CentralWidget::glassTransitionHandle2() { QPointF point1 = PointCalculate::getClosestPointByX(_line1->point1->coords().x()); QPointF point2 = PointCalculate::getClosestPointByX(_line2->point1->coords().x()); logde<<"point1:"< point1Vtr = PointCalculate::getNearbyPointGroupByX(point1.x()); QVector point2Vtr = PointCalculate::getNearbyPointGroupByX(point2.x()); QVector xVtr,yVtr; for(QPointF &p:point1Vtr){ xVtr.append(p.x()); yVtr.append(p.y()); } PointCalculate::Line line1 = calculateLinearRegression(xVtr,yVtr); #if 1 ///line1 // QVector xVtr,yVtr; xVtr.clear(); yVtr.clear(); xVtr.push_back(point1.x()); yVtr.push_back(point1.y()); xVtr.push_back(point1.x() + 10); double y1 = line1.slope * (point1.x() + 10) + line1.intercept; yVtr.push_back(y1); QCPGraph *lineGraph1 = _customPlot->addGraph(); lineGraph1->setData(xVtr, yVtr); QPen pen; pen.setColor(Qt::darkGreen); lineGraph1->setPen(pen); #endif xVtr.clear(); yVtr.clear(); for(QPointF &p:point2Vtr){ xVtr.append(p.x()); yVtr.append(p.y()); } PointCalculate::Line line2 = calculateLinearRegression(xVtr,yVtr); #if 1 ///line2 QVector xVtr2,yVtr2; xVtr2.push_back(point2.x()); yVtr2.push_back(point2.y()); xVtr2.push_back(point2.x() - 10); double y2 = line2.slope * (point2.x() - 10) + line2.intercept; yVtr2.push_back(y2); QCPGraph *lineGraph2 = _customPlot->addGraph(); lineGraph2->setData(xVtr2, yVtr2); lineGraph2->setPen(pen); _customPlot->replot(); #endif // inflection point. QVector originalPointVtr = PointCalculate::getPointVtrInXRange(point1.x(),point2.x()); // QVector pointVtr = PointCalculate::movingAveragePoint(originalPointVtr,3); QVector pointVtr = originalPointVtr; xVtr.clear(); yVtr.clear(); for(QPointF& p:pointVtr){ xVtr.append(p.x()); yVtr.append(p.y()); } QMap tangentLines = PointCalculate::calculateTangentLine(xVtr,yVtr); double targetX = 0.0; PointCalculate::Line targetLine; double maxSlopeAbs = 0.0; // 初始化最大斜率绝对值为0 #if 0 for (auto it = tangentLines.begin(); it != tangentLines.end(); ++it) { if (std::fabs(it.value().slope) > maxSlopeAbs) { maxSlopeAbs = std::fabs(it.value().slope); // 更新最大斜率绝对值 targetX = it.key(); targetLine = it.value(); } } #endif // new method for (auto it = tangentLines.begin(); it != tangentLines.end(); ++it) { if (std::fabs(it.value().slope) > maxSlopeAbs) { maxSlopeAbs = std::fabs(it.value().slope); // 更新最大斜率绝对值 targetX = it.key(); targetLine = it.value(); } } int index = 0; QPointF prePoint,currentPoint,lastPoint; for (int i = 0;i < pointVtr.size();i++) { currentPoint = pointVtr[i]; if(currentPoint.x() == targetX){ index = i; break; } } prePoint = pointVtr[index - 1]; lastPoint = pointVtr[index + 1]; targetLine.slope = PointCalculate::calculateSlope(lastPoint.x(),lastPoint.y(),prePoint.x(),prePoint.y()); targetLine.intercept = currentPoint.y() - targetLine.slope * currentPoint.x(); // #if 1 QPointF intersection1 = PointCalculate::getIntersection(targetLine,line1); QPointF intersection2 = PointCalculate::getIntersection(targetLine,line2); // graph 3 xVtr.clear(); yVtr.clear(); #if 0 xVtr.push_back(point1.x()); yVtr.push_back(point1.y()); xVtr.push_back(point1.x()); yVtr.push_back(point1.y()); #endif #if 1 xVtr.push_back(intersection1.x()); yVtr.push_back(intersection1.y()); xVtr.push_back(intersection2.x()); yVtr.push_back(intersection2.y()); #endif QCPGraph *lineGraph3 = _customPlot->addGraph(); lineGraph3->setData(xVtr, yVtr); lineGraph3->setPen(pen); #endif _customPlot->replot(); // point value double averageY = (point1.y() + point2.y()) / 2; QPointF averagePoint = PointCalculate::getClosestPointByY(point1.x(),point2.x(),averageY); QString str = PointCalculate::textFormatGlassTranstion(intersection1.x(), averagePoint.x(), intersection2.x()); drawText(averagePoint,str); } // 使用最小二乘法计算线性回归 PointCalculate::Line CentralWidget::calculateLinearRegression(const QVector& x, const QVector& y) { PointCalculate::Line line; double sum_x = 0, sum_y = 0, sum_xy = 0, sum_xx = 0; size_t n = x.size(); // 计算所需的总和 for (size_t i = 0; i < n; ++i) { sum_x += x[i]; sum_y += y[i]; sum_xy += x[i] * y[i]; sum_xx += x[i] * x[i]; } // 计算斜率和截距 double x_mean = sum_x / n; double y_mean = sum_y / n; double numerator = n * sum_xy - sum_x * sum_y; double denominator = n * sum_xx - sum_x * sum_x; line.slope = numerator / denominator; line.intercept = y_mean - line.slope * x_mean; return line; } // 二次多项式拟合函数 void CentralWidget::quadraticFit(const QVector& points, double& a, double& b, double& c) { int n = points.size(); if (n < 3) { throw std::invalid_argument("At least three points are required for quadratic fit."); } double sumX = 0, sumY = 0, sumXX = 0, sumXY = 0, sumX2Y = 0; for (const QPointF& p : points) { sumX += p.x(); sumY += p.y(); sumXX += p.x() * p.x(); sumXY += p.x() * p.y(); sumX2Y += p.x() * p.x() * p.y(); } double det = n * (sumXX * sumY - sumX * sumXY) - sumX * sumX * sumY + sumX * sumX2Y; a = (sumXX * sumY - sumX * sumXY) / det; b = (sumX2Y - n * sumXY) / det; c = (sumY - a * sumX - b * sumX) / n; } // 计算二次多项式拟合曲线的导数(切线斜率) double CentralWidget::derivativeAt(const double a, const double b, const double x) { return 2 * a * x + b; } void CentralWidget::setEventHandlerEnable(const bool flag) { logde<<"setEventHandlerEnable..."<setSelected(flag); line->setVisible(flag); }; // todo. 当竖线隐藏时,需要设置不可选择模式。 // _eventHandler->setEnable(flag); #if 1 // move line to suitable position. double xMax = _customPlot->xAxis->range().upper; double xMin = _customPlot->xAxis->range().lower; // logde<<"xMax:"< ticks = _customPlot->xAxis->tickVector(); // int numTicks = ticks.size(); // logde<<"ticks:"<point1->setCoords(xLeft,_line1->point1->coords().y()); _line1->point2->setCoords(xLeft,_line1->point2->coords().y()); _line2->point1->setCoords(xRight,_line2->point1->coords().y()); _line2->point2->setCoords(xRight,_line2->point2->coords().y()); #endif lineVisiableFunc(_line1); if(AnalysisMode::NumericalLabel != _analysisMode){ lineVisiableFunc(_line2); } // _customPlot->replot(); } QPointF CentralWidget::getTheCoordinatesOfTheTextBox(const QPointF point) { double xMax = _customPlot->xAxis->range().upper; double xMin = _customPlot->xAxis->range().lower; logde<<"xMax:"< ticks = _customPlot->xAxis->tickVector(); int numTicks = ticks.size(); logde<<"ticks:"<setPositionAlignment(Qt::AlignCenter); // 对齐方式 textLabel->position->setType(QCPItemPosition::ptPlotCoords); // 使用数据坐标 textLabel->position->setCoords(textBoxPoint.x(),textBoxPoint.y()); // 设置文本位置在指定点上方 textLabel->setText(text); // 设置文本内容 QFont font(QFont("Arial", 10)); textLabel->setFont(font); textLabel->setSelectedFont(font); textLabel->setSelectable(true); // 设置为可选 // 创建指向点的线段(QCPItemLine) QCPItemLine *arrow = new QCPItemLine(_customPlot); arrow->start->setParentAnchor(textLabel->left); // 线段起点绑定到标注文字底部 arrow->end->setCoords(point.x(),point.y()); // 线段终点设置为指定的点 arrow->setHead(QCPLineEnding::esSpikeArrow); // 添加箭头 arrow->setPen(QPen(Qt::red, 1)); // 重绘图表以显示文本标签和箭头 _customPlot->replot(); } void CentralWidget::fillGraph(const double x1, const double x2) { double y1 = PointCalculate::getClosestPointByX(x1).y(); double y2 = PointCalculate::getClosestPointByX(x2).y(); QVector xVtr,yVtr; xVtr.push_back(x1); xVtr.push_back(x2); yVtr.push_back(y1); yVtr.push_back(y2); QCPGraph *mainGraph = _customPlot->addGraph(); mainGraph->setData(xVtr, yVtr); mainGraph->setPen(QPen(Qt::red, 1)); QVector curveDataVtr = PointCalculate::getDataInXRange(x1,x2); QCPGraph *fillGraph = _customPlot->addGraph(); QVector fillX, fillY; for(int i = 0;i < curveDataVtr.size();i++){ Global::ExperimentData &ed = curveDataVtr[i]; fillX<setData(fillX, fillY); fillGraph->setBrush(QBrush(Qt::green, Qt::SolidPattern)); fillGraph->setChannelFillGraph(mainGraph); _customPlot->replot(); } void CentralWidget::clearData(const CentralWidget::ClearDataMode mode) { if(mode == ClearDataMode::All){ // Clear the data of graph. for (int i = _customPlot->plottableCount() - 1; i >= 0; --i) { QCPAbstractPlottable* plottable = _customPlot->plottable(i); if (auto curve = dynamic_cast(plottable)) { _customPlot->removePlottable(curve); } } // Clear data. Global::_curveExperimentDataVtr.clear(); // Set lines visiable false. _line1->setVisible(false); _line2->setVisible(false); } #if 0 // Clear graph on plot. for (int i = _customPlot->graphCount() - 1; i >= 0; --i) { QCPGraph *graph = _customPlot->graph(i); _customPlot->removeGraph(graph); } _currentCurve = nullptr; #endif // Delete items. QList itemsToKeep; itemsToKeep << _line1 << _line2; for (int i = _customPlot->itemCount() - 1; i >= 0; --i) { QCPAbstractItem *item = _customPlot->item(i); if (!itemsToKeep.contains(item)) { _customPlot->removeItem(item); } } // 重绘图表以显示更改 _customPlot->replot(); } void CentralWidget::clearAllData() { clearData(ClearDataMode::All); } QPixmap CentralWidget::getPixMap() { return _customPlot->toPixmap(); } void CentralWidget::slotAxisModify(const float temp) { _customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables); float value = temp + 20; _customPlot->xAxis->setRange(10,value); _customPlot->yAxis->setRange(-5,5); }