void WindPlot::updatePlot() { clearPlottables(); clearItems(); // Return now if plot empty if (mMainWindow->dataSize() == 0) return; double lower = mMainWindow->rangeLower(); double upper = mMainWindow->rangeUpper(); QVector< double > t, x, y; double xMin, xMax; double yMin, yMax; int start = mMainWindow->findIndexBelowT(lower) + 1; int end = mMainWindow->findIndexAboveT(upper); bool first = true; for (int i = start; i < end; ++i) { const DataPoint &dp = mMainWindow->dataPoint(i); t.append(dp.t); if (mMainWindow->units() == PlotValue::Metric) { x.append(dp.velE * MPS_TO_KMH); y.append(dp.velN * MPS_TO_KMH); } else { x.append(dp.velE * MPS_TO_MPH); y.append(dp.velN * MPS_TO_MPH); } if (first) { xMin = xMax = x.back(); yMin = yMax = y.back(); first = false; } else { if (x.back() < xMin) xMin = x.back(); if (x.back() > xMax) xMax = x.back(); if (y.back() < yMin) yMin = y.back(); if (y.back() > yMax) yMax = y.back(); } } QCPCurve *curve = new QCPCurve(xAxis, yAxis); curve->setData(t, x, y); curve->setPen(QPen(Qt::lightGray, mMainWindow->lineThickness())); setViewRange(xMin, xMax, yMin, yMax); if (mMainWindow->markActive()) { const DataPoint &dpEnd = mMainWindow->interpolateDataT(mMainWindow->markEnd()); t.clear(); x.clear(); y.clear(); QVector< double > xMark, yMark; if (mMainWindow->units() == PlotValue::Metric) { xMark.append(dpEnd.velE * MPS_TO_KMH); yMark.append(dpEnd.velN * MPS_TO_KMH); } else { xMark.append(dpEnd.velE * MPS_TO_MPH); yMark.append(dpEnd.velN * MPS_TO_MPH); } QCPGraph *graph = addGraph(); graph->setData(xMark, yMark); graph->setPen(QPen(Qt::black, mMainWindow->lineThickness())); graph->setLineStyle(QCPGraph::lsNone); graph->setScatterStyle(QCPScatterStyle::ssDisc); } updateWind(start, end); QVector< double > xMark, yMark; if (mMainWindow->units() == PlotValue::Metric) { xMark.append(mWindE * MPS_TO_KMH); yMark.append(mWindN * MPS_TO_KMH); } else { xMark.append(mWindE * MPS_TO_MPH); yMark.append(mWindN * MPS_TO_MPH); } QCPGraph *graph = addGraph(); graph->setData(xMark, yMark); graph->setPen(QPen(Qt::red, mMainWindow->lineThickness())); graph->setLineStyle(QCPGraph::lsNone); graph->setScatterStyle(QCPScatterStyle::ssDisc); const double x0 = mWindE; const double y0 = mWindN; const double r = mVelAircraft; QVector< double > tCircle, xCircle, yCircle; for (int i = 0; i <= 100; ++i) { tCircle.append(i); const double x = x0 + r * cos((double) i / 100 * 2 * M_PI); const double y = y0 + r * sin((double) i / 100 * 2 * M_PI); if (mMainWindow->units() == PlotValue::Metric) { xCircle.append(x * MPS_TO_KMH); yCircle.append(y * MPS_TO_KMH); } else { xCircle.append(x * MPS_TO_MPH); yCircle.append(y * MPS_TO_MPH); } } curve = new QCPCurve(xAxis, yAxis); curve->setData(tCircle, xCircle, yCircle); curve->setPen(QPen(Qt::red, mMainWindow->lineThickness())); // Add label to show best fit QCPItemText *textLabel = new QCPItemText(this); const double factor = (mMainWindow->units() == PlotValue::Metric) ? MPS_TO_KMH : MPS_TO_MPH; const QString units = (mMainWindow->units() == PlotValue::Metric) ? "km/h" : "mph"; double direction = atan2(-mWindE, -mWindN) / M_PI * 180.0; if (direction < 0) direction += 360.0; QPainter painter(this); double mmPerPix = (double) painter.device()->widthMM() / painter.device()->width(); double xRatioPerPix = 1.0 / axisRect()->width(); double xRatioPerMM = xRatioPerPix / mmPerPix; double yRatioPerPix = 1.0 / axisRect()->height(); double yRatioPerMM = yRatioPerPix / mmPerPix; textLabel->setPositionAlignment(Qt::AlignBottom|Qt::AlignRight); textLabel->setTextAlignment(Qt::AlignRight); textLabel->position->setType(QCPItemPosition::ptAxisRectRatio); textLabel->position->setCoords(1 - 5 * xRatioPerMM, 1 - 5 * yRatioPerMM); textLabel->setText( QString("Wind speed = %1 %2\nWind direction = %3 deg\nAircraft speed = %4 %5") .arg(sqrt(mWindE * mWindE + mWindN * mWindN) * factor) .arg(units) .arg(direction) .arg(mVelAircraft * factor) .arg(units)); replot(); }
void AdvancedQCustomPlot::wheelEvent(QWheelEvent *event) { if (event->modifiers() == Qt::ShiftModifier){ axisRect()->setRangeZoom(Qt::Vertical); } else if (event->modifiers() == Qt::ControlModifier){ axisRect()->setRangeZoom(Qt::Horizontal); } else { axisRect()->setRangeZoom(Qt::Vertical | Qt::Horizontal); } isZoomed_ = true; QCustomPlot::wheelEvent(event); }
QCustomPlotExt::QCustomPlotExt(QWidget *parent) : QCustomPlot(parent), marker(NULL) { clearExt(); setInteractions(QCP::iRangeDrag | QCP::iRangeZoom); axisRect()->setRangeDrag(Qt::Horizontal | Qt::Vertical); axisRect()->setRangeZoom(Qt::Horizontal | Qt::Vertical); connect(this, SIGNAL(mouseWheel(QWheelEvent*)), this, SLOT(mouseWheel(QWheelEvent*))); connect(xAxis, SIGNAL(rangeChanged(QCPRange)), this, SLOT(xAxisRangeChanged(QCPRange))); connect(yAxis, SIGNAL(rangeChanged(QCPRange)), this, SLOT(yAxisRangeChanged(QCPRange))); }
Graph::Graph(QWidget *parent) : QWidget(parent) , mPlotArea_(0) , mHBar_(0) , mVBar_(0) , mTitle_("Title") , mGridX_(0) , mGridY_(0) , mDragging_(false) , mMarker_(0) , mLabel_(0) { ui.setupUi(this); mPaintBuffer_ = QPixmap(size()); mPlotArea_ = new QFrame(this); mPlotArea_->setGeometry(axisRect().adjusted(3, 0, 0, -3)); mPlotArea_->setFrameStyle(QFrame::Sunken); mPlotArea_->setFrameShape(QFrame::Panel); mPlotArea_->setLineWidth(2); GraphLayer* axisLayer = new GraphLayer(); GraphAxis* axisX = new GraphAxis(axisRect(), GraphAxis::AT_BOTTOM); axisX->setLabel("sec"); GraphAxis* axisY = new GraphAxis(axisRect(), GraphAxis::AT_LEFT); axisY->setLabel("pressure"); axisX->setLayer(axisLayer); axisY->setLayer(axisLayer); mAxisXs_.append(axisX); mAxisYs_.append(axisY); mLayers_.append(axisLayer); GraphLayer* gridLayer = new GraphLayer(); mGridX_ = new GraphGrid(mAxisXs_); mGridY_ = new GraphGrid(mAxisYs_); mGridX_->setLayer(gridLayer); mGridY_->setLayer(gridLayer); mLayers_.append(gridLayer); GraphLayer* markerLayer = new GraphLayer(); mMarker_ = new GraphMarker(axisRect()); mMarker_->setLayer(markerLayer); mLayers_.append(markerLayer); mHBar_ = new GraphBar(this, *mAxisXs_.first()); connect(mHBar_, SIGNAL(valueChanged(int)), this, SLOT(hBarValueChanged(int))); mVBar_ = new GraphBar(this, *mAxisYs_.first()); connect(mVBar_, SIGNAL(valueChanged(int)), this, SLOT(vBarValueChanged(int))); mLabel_ = new GraphLabel(this, axisRect()); }
void WindPlot::setViewRange( double xMin, double xMax, double yMin, double yMax) { QPainter painter(this); double xMMperPix = (double) painter.device()->widthMM() / painter.device()->width(); double yMMperPix = (double) painter.device()->heightMM() / painter.device()->height(); QRect rect = axisRect()->rect(); double xSpan = (xMax - xMin) * 1.2; double ySpan = (yMax - yMin) * 1.2; double xScale = xSpan / rect.width() / xMMperPix; double yScale = ySpan / rect.height() / yMMperPix; double scale = qMax(xScale, yScale); double xMid = (xMin + xMax) / 2; double yMid = (yMin + yMax) / 2; xMin = xMid - rect.width() * xMMperPix * scale / 2; xMax = xMid + rect.width() * xMMperPix * scale / 2; yMin = yMid - rect.height() * yMMperPix * scale / 2; yMax = yMid + rect.height() * yMMperPix * scale / 2; xAxis->setRange(xMin, xMax); yAxis->setRange(yMin, yMax); }
void TgChart::mouseMoveEvent(QMouseEvent * event) { if (mRubberBand->isVisible()) { mRubberBand->setGeometry(QRect(mOrigin, QPoint(event->pos().x(),axisRect()->bottomRight().y())).normalized()); } QCustomPlot::mouseMoveEvent(event); }
void QCustomPlotExt::mouseWheel(QWheelEvent *event) { if (event->modifiers()& Qt::ShiftModifier) { axisRect()->setRangeZoom(Qt::Vertical); } else if (event->delta() < 0 && xAxisRangeOrg == xAxis->range()) { axisRect()->setRangeZoom(0); } else { if (event->modifiers()& Qt::ControlModifier) axisRect()->setRangeZoom(Qt::Horizontal); else axisRect()->setRangeZoom(Qt::Horizontal | Qt::Vertical); } }
void LiftDragPlot::mousePressEvent( QMouseEvent *event) { if (axisRect()->rect().contains(event->pos())) { mBeginPos = event->pos(); } QCustomPlot::mousePressEvent(event); }
DrawInteraction::DrawInteraction(QWidget *parent) : QCustomPlot(parent) { resize(600,400); statusBar = new QStatusBar(this); srand(QDateTime::currentDateTime().toTime_t()); setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectAxes | QCP::iSelectLegend | QCP::iSelectPlottables); xAxis->setRange(-8, 8); yAxis->setRange(-5, 5); axisRect()->setupFullAxesBox(); plotLayout()->insertRow(0); plotLayout()->addElement(0, 0, new QCPPlotTitle(this, "Interaction Example")); xAxis->setLabel("x Axis"); yAxis->setLabel("y Axis"); legend->setVisible(true); QFont legendFont = font(); legendFont.setPointSize(10); legend->setFont(legendFont); legend->setSelectedFont(legendFont); legend->setSelectableParts(QCPLegend::spItems); // legend box shall not be selectable, only legend items addRandomGraph(); addRandomGraph(); addRandomGraph(); addRandomGraph(); // connect slot that ties some axis selections together (especially opposite axes): connect(this, SIGNAL(selectionChangedByUser()), this, SLOT(selectionChanged())); // connect slots that takes care that when an axis is selected, only that direction can be dragged and zoomed: connect(this, SIGNAL(mousePress(QMouseEvent*)), this, SLOT(mousePress())); connect(this, SIGNAL(mouseWheel(QWheelEvent*)), this, SLOT(mouseWheel())); // make bottom and left axes transfer their ranges to top and right axes: connect(xAxis, SIGNAL(rangeChanged(QCPRange)), xAxis2, SLOT(setRange(QCPRange))); connect(yAxis, SIGNAL(rangeChanged(QCPRange)), yAxis2, SLOT(setRange(QCPRange))); // connect some interaction slots: connect(this, SIGNAL(titleDoubleClick(QMouseEvent*,QCPPlotTitle*)), this, SLOT(titleDoubleClick(QMouseEvent*,QCPPlotTitle*))); connect(this, SIGNAL(axisDoubleClick(QCPAxis*,QCPAxis::SelectablePart,QMouseEvent*)), this, SLOT(axisLabelDoubleClick(QCPAxis*,QCPAxis::SelectablePart))); connect(this, SIGNAL(legendDoubleClick(QCPLegend*,QCPAbstractLegendItem*,QMouseEvent*)), this, SLOT(legendDoubleClick(QCPLegend*,QCPAbstractLegendItem*))); // connect slot that shows a message in the status bar when a graph is clicked: connect(this, SIGNAL(plottableClick(QCPAbstractPlottable*,QMouseEvent*)), this, SLOT(graphClicked(QCPAbstractPlottable*))); // setup policy and connect slot for context menu popup: setContextMenuPolicy(Qt::CustomContextMenu); connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuRequest(QPoint))); }
void QCustomPlotExt::mousePress(QMouseEvent* event) { if (event->button() == Qt::LeftButton) { if (marker) { if(axisRect()->rect().contains(event->pos())) setMarkerValue(xAxis->pixelToCoord(event->x())); } } }
void TgChart::mousePressEvent(QMouseEvent * event) { if (mZoomMode) { if ( event->button() == Qt::MiddleButton) { mOrigin = QPoint(event->pos().x(),axisRect()->topLeft().y()); mRubberBand->setGeometry(QRect(mOrigin, QSize())); mRubberBand->show(); } } QCustomPlot::mousePressEvent(event); }
void LiftDragPlot::updatePlot() { clearPlottables(); clearItems(); xAxis->setLabel(tr("Drag Coefficient")); yAxis->setLabel(tr("Lift Coefficient")); double lower = mMainWindow->rangeLower(); double upper = mMainWindow->rangeUpper(); QVector< double > t, x, y; double xMin, xMax; double yMin, yMax; int start = mMainWindow->findIndexBelowT(lower) + 1; int end = mMainWindow->findIndexAboveT(upper); double s10 = 0, s01 = 0, s20 = 0, s11 = 0; double s21 = 0, s30 = 0, s40 = 0; bool first = true; for (int i = start; i < end; ++i) { const DataPoint &dp = mMainWindow->dataPoint(i); t.append(dp.t); x.append(dp.drag); y.append(dp.lift); if (first) { xMax = x.back(); yMax = y.back(); first = false; } else { if (x.back() > xMax) xMax = x.back(); if (y.back() > yMax) yMax = y.back(); } s10 += dp.lift; s01 += dp.drag; s20 += dp.lift * dp.lift; s11 += dp.lift * dp.drag; s21 += dp.lift * dp.lift * dp.drag; s30 += dp.lift * dp.lift * dp.lift; s40 += dp.lift * dp.lift * dp.lift * dp.lift; } QCPCurve *curve = new QCPCurve(xAxis, yAxis); curve->setData(t, x, y); curve->setPen(QPen(Qt::lightGray, mMainWindow->lineThickness())); curve->setLineStyle(QCPCurve::lsNone); curve->setScatterStyle(QCPScatterStyle::ssDisc); addPlottable(curve); setViewRange(xMax, yMax); // Update plot limits xMin = xAxis->range().lower; xMax = xAxis->range().upper; yMin = yAxis->range().lower; yMax = yAxis->range().upper; if (mMainWindow->markActive()) { int i1 = mMainWindow->findIndexBelowT(mMainWindow->markEnd()) + 1; int i2 = mMainWindow->findIndexAboveT(mMainWindow->markEnd()) - 1; const DataPoint &dp1 = mMainWindow->dataPoint(i1); const DataPoint &dp2 = mMainWindow->dataPoint(i2); QVector< double > xMark, yMark; if (mMainWindow->markEnd() - dp1.t < dp2.t - mMainWindow->markEnd()) { xMark.append(dp1.drag); yMark.append(dp1.lift); } else { xMark.append(dp2.drag); yMark.append(dp2.lift); } QCPGraph *graph = addGraph(); graph->setData(xMark, yMark); graph->setPen(QPen(Qt::black, mMainWindow->lineThickness())); graph->setLineStyle(QCPGraph::lsNone); graph->setScatterStyle(QCPScatterStyle::ssDisc); } // x = ay^2 + c const double m = 1 / mMainWindow->maxLD(); const double c = mMainWindow->minDrag(); const double a = m * m / (4 * c); // Draw tangent line const double yt = sqrt(c / a); if (a != 0) { x.clear(); y.clear(); x << m * yMin << m * yMax; y << yMin << yMax; QCPGraph *graph = addGraph(); graph->setData(x, y); graph->setPen(QPen(Qt::blue, mMainWindow->lineThickness(), Qt::DashLine)); } // Draw minimum drag x.clear(); y.clear(); x << mMainWindow->minDrag() << mMainWindow->minDrag(); y << yMin << yMax; QCPGraph *graph = addGraph(); graph->setData(x, y); graph->setPen(QPen(Qt::blue, mMainWindow->lineThickness(), Qt::DashLine)); // Draw maximum lift x.clear(); y.clear(); x << xMin << xMax; y << mMainWindow->maxLift() << mMainWindow->maxLift(); graph = addGraph(); graph->setData(x, y); graph->setPen(QPen(Qt::blue, mMainWindow->lineThickness(), Qt::DashLine)); // Draw saved curve t.clear(); x.clear(); y.clear(); for (int i = 0; i <= 100; ++i) { const double yy = yMin + (yMax - yMin) / 100 * i; t.append(yy); x.append(a * yy * yy + c); y.append(yy); } curve = new QCPCurve(xAxis, yAxis); curve->setData(t, x, y); curve->setPen(QPen(Qt::red, mMainWindow->lineThickness())); addPlottable(curve); // Draw dot at maximum L/D x.clear(); y.clear(); x << a * yt * yt + c; y << yt; graph = addGraph(); graph->setData(x, y); graph->setPen(QPen(Qt::red, mMainWindow->lineThickness())); graph->setLineStyle(QCPGraph::lsNone); graph->setScatterStyle(QCPScatterStyle::ssDisc); // Add label to show equation for saved curve QCPItemText *textLabel = new QCPItemText(this); addItem(textLabel); QPainter painter(this); double mmPerPix = (double) painter.device()->widthMM() / painter.device()->width(); double xRatioPerPix = 1.0 / axisRect()->width(); double xRatioPerMM = xRatioPerPix / mmPerPix; double yRatioPerPix = 1.0 / axisRect()->height(); double yRatioPerMM = yRatioPerPix / mmPerPix; textLabel->setPositionAlignment(Qt::AlignBottom|Qt::AlignRight); textLabel->setTextAlignment(Qt::AlignRight); textLabel->position->setType(QCPItemPosition::ptAxisRectRatio); textLabel->position->setCoords(1 - 5 * xRatioPerMM, 1 - 5 * yRatioPerMM); textLabel->setText( QString("Minimum drag = %1\nMaximum lift = %2\nMaximum L/D = %3") .arg(fabs(c)) .arg(mMainWindow->maxLift()) .arg(1/ m)); replot(); }
DrawFinancialChart::DrawFinancialChart(QWidget *parent) : QCustomPlot(parent) { resize(600,400); legend->setVisible(true); // generate two sets of random walk data (one for candlestick and one for ohlc chart): int n = 500; QVector<double> time(n), value1(n), value2(n); QDateTime start = QDateTime(QDate(2014, 6, 11)); start.setTimeSpec(Qt::UTC); double startTime = start.toTime_t(); double binSize = 3600*24; // bin data in 1 day intervals time[0] = startTime; value1[0] = 60; value2[0] = 20; qsrand(9); for (int i=1; i<n; ++i) { time[i] = startTime + 3600*i; value1[i] = value1[i-1] + (qrand()/(double)RAND_MAX-0.5)*10; value2[i] = value2[i-1] + (qrand()/(double)RAND_MAX-0.5)*3; } // create candlestick chart: QCPFinancial *candlesticks = new QCPFinancial(xAxis, yAxis); addPlottable(candlesticks); QCPFinancialDataMap data1 = QCPFinancial::timeSeriesToOhlc(time, value1, binSize, startTime); candlesticks->setName("Candlestick"); candlesticks->setChartStyle(QCPFinancial::csCandlestick); candlesticks->setData(&data1, true); candlesticks->setWidth(binSize*0.9); candlesticks->setTwoColored(true); candlesticks->setBrushPositive(QColor(245, 245, 245)); candlesticks->setBrushNegative(QColor(0, 0, 0)); candlesticks->setPenPositive(QPen(QColor(0, 0, 0))); candlesticks->setPenNegative(QPen(QColor(0, 0, 0))); // create ohlc chart: QCPFinancial *ohlc = new QCPFinancial(xAxis, yAxis); addPlottable(ohlc); QCPFinancialDataMap data2 = QCPFinancial::timeSeriesToOhlc(time, value2, binSize/3.0, startTime); // divide binSize by 3 just to make the ohlc bars a bit denser ohlc->setName("OHLC"); ohlc->setChartStyle(QCPFinancial::csOhlc); ohlc->setData(&data2, true); ohlc->setWidth(binSize*0.2); ohlc->setTwoColored(true); // create bottom axis rect for volume bar chart: QCPAxisRect *volumeAxisRect = new QCPAxisRect(this); plotLayout()->addElement(1, 0, volumeAxisRect); volumeAxisRect->setMaximumSize(QSize(QWIDGETSIZE_MAX, 100)); volumeAxisRect->axis(QCPAxis::atBottom)->setLayer("axes"); volumeAxisRect->axis(QCPAxis::atBottom)->grid()->setLayer("grid"); // bring bottom and main axis rect closer together: plotLayout()->setRowSpacing(0); volumeAxisRect->setAutoMargins(QCP::msLeft|QCP::msRight|QCP::msBottom); volumeAxisRect->setMargins(QMargins(0, 0, 0, 0)); // create two bar plottables, for positive (green) and negative (red) volume bars: QCPBars *volumePos = new QCPBars(volumeAxisRect->axis(QCPAxis::atBottom), volumeAxisRect->axis(QCPAxis::atLeft)); QCPBars *volumeNeg = new QCPBars(volumeAxisRect->axis(QCPAxis::atBottom), volumeAxisRect->axis(QCPAxis::atLeft)); for (int i=0; i<n/5; ++i) { int v = qrand()%20000+qrand()%20000+qrand()%20000-10000*3; (v < 0 ? volumeNeg : volumePos)->addData(startTime+3600*5.0*i, qAbs(v)); // add data to either volumeNeg or volumePos, depending on sign of v } setAutoAddPlottableToLegend(false); addPlottable(volumePos); addPlottable(volumeNeg); volumePos->setWidth(3600*4); volumePos->setPen(Qt::NoPen); volumePos->setBrush(QColor(100, 180, 110)); volumeNeg->setWidth(3600*4); volumeNeg->setPen(Qt::NoPen); volumeNeg->setBrush(QColor(180, 90, 90)); // interconnect x axis ranges of main and bottom axis rects: connect(xAxis, SIGNAL(rangeChanged(QCPRange)), volumeAxisRect->axis(QCPAxis::atBottom), SLOT(setRange(QCPRange))); connect(volumeAxisRect->axis(QCPAxis::atBottom), SIGNAL(rangeChanged(QCPRange)), xAxis, SLOT(setRange(QCPRange))); // configure axes of both main and bottom axis rect: volumeAxisRect->axis(QCPAxis::atBottom)->setAutoTickStep(false); volumeAxisRect->axis(QCPAxis::atBottom)->setTickStep(3600*24*4); // 4 day tickstep volumeAxisRect->axis(QCPAxis::atBottom)->setTickLabelType(QCPAxis::ltDateTime); volumeAxisRect->axis(QCPAxis::atBottom)->setDateTimeSpec(Qt::UTC); volumeAxisRect->axis(QCPAxis::atBottom)->setDateTimeFormat("dd. MMM"); volumeAxisRect->axis(QCPAxis::atBottom)->setTickLabelRotation(15); volumeAxisRect->axis(QCPAxis::atLeft)->setAutoTickCount(3); xAxis->setBasePen(Qt::NoPen); xAxis->setTickLabels(false); xAxis->setTicks(false); // only want vertical grid in main axis rect, so hide xAxis backbone, ticks, and labels xAxis->setAutoTickStep(false); xAxis->setTickStep(3600*24*4); // 4 day tickstep rescaleAxes(); xAxis->scaleRange(1.025, xAxis->range().center()); yAxis->scaleRange(1.1, yAxis->range().center()); // make axis rects' left side line up: QCPMarginGroup *group = new QCPMarginGroup(this); axisRect()->setMarginGroup(QCP::msLeft|QCP::msRight, group); volumeAxisRect->setMarginGroup(QCP::msLeft|QCP::msRight, group); }