Пример #1
0
void QCustomPlotExt::addMarker(const QPen &pen)
{
    const QVector<double> markerValues = QVector<double>() << 0 << 0;
    marker = new QCPCurve(xAxis, yAxis);
    marker->setPen(pen);
    marker->setData(markerValues, markerValues);
    addPlottable(marker);
    connect(this, SIGNAL(mousePress(QMouseEvent*)), this, SLOT(mousePress(QMouseEvent*)));
    markerValue = 0.0;
}
Пример #2
0
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();
}
Пример #3
0
void ccHistogramWindow::refresh()
{
	// set ranges appropriate to show data
	double minVal = m_minVal;
	double maxVal = m_maxVal;
	if (m_sfInteractionMode && m_associatedSF)
	{
		double minSat = m_associatedSF->saturationRange().min();
		double maxSat = m_associatedSF->saturationRange().max();
		minVal = std::min(minVal,minSat);
		maxVal = std::max(maxVal,maxSat);
	}
	xAxis->setRange(minVal, maxVal);
	yAxis->setRange(0, m_maxHistoVal);

	if (!m_titleStr.isEmpty())
	{
		// add title layout element
		if (!m_titlePlot)
		{
			//add a row for the title
			plotLayout()->insertRow(0);
		}
		else
		{
			//remove previous title
			plotLayout()->remove(m_titlePlot);
			m_titlePlot = 0;
		}
		m_titlePlot = new QCPPlotTitle(this, QString("%0 [%1 classes]").arg(m_titleStr).arg(m_histoValues.size()));
		//title font
		m_renderingFont.setPointSize(ccGui::Parameters().defaultFontSize);
		m_titlePlot->setFont(m_renderingFont);
		plotLayout()->addElement(0, 0, m_titlePlot);
	}

	//clear previous display
	m_histogram		= 0;
	m_vertBar		= 0;
	m_overlayCurve	= 0;
	m_areaLeft		= 0;
	m_areaRight		= 0;
	m_arrowLeft		= 0;
	m_arrowRight	= 0;
	this->clearGraphs();
	this->clearPlottables();

	if (m_histoValues.empty())
		return;

	//default color scale to be used for display
	ccColorScale::Shared colorScale = (m_colorScale ? m_colorScale : ccColorScalesManager::GetDefaultScale());

	//histogram
	int histoSize = static_cast<int>(m_histoValues.size());
	double totalSum = 0;
	double partialSum = 0;
	if (histoSize > 0)
	{
		m_histogram = new QCPColoredBars(xAxis, yAxis);
		addPlottable(m_histogram);
		// now we can modify properties of myBars:
		m_histogram->setWidth((m_maxVal - m_minVal) / histoSize);
		m_histogram->setAntialiasedFill(false);
		QVector<double> keyData(histoSize);
		QVector<double> valueData(histoSize);

		HISTOGRAM_COLOR_SCHEME colorScheme = m_colorScheme;
		switch(colorScheme)
		{
		case USE_SOLID_COLOR:
			m_histogram->setBrush(QBrush(m_solidColor,Qt::SolidPattern));
			m_histogram->setPen(QPen(m_solidColor));
			break;
		case USE_CUSTOM_COLOR_SCALE:
			//nothing to do
			break;
		case USE_SF_SCALE:
			if (m_associatedSF && m_associatedSF->getColorScale())
			{
				//we use the SF's color scale
				colorScale = m_associatedSF->getColorScale();
			}
			else
			{
				//we'll use the default one...
				assert(false);
				colorScheme = USE_CUSTOM_COLOR_SCALE;
			}
			break;
		default:
			assert(false);
			colorScheme = USE_CUSTOM_COLOR_SCALE;
			break;
		}

		QVector<QColor> colors;
		if (colorScheme != USE_SOLID_COLOR)
		{
			colors.resize(histoSize);
		}

		for (int i=0; i<histoSize; ++i)
		{
			//we take the 'normalized' value at the middle of the class
			double normVal = (static_cast<double>(i)+0.5) / histoSize;

			totalSum += m_histoValues[i];
			if (normVal < m_verticalIndicatorPositionPercent)
				partialSum += m_histoValues[i];

			keyData[i] = m_minVal + normVal * (m_maxVal - m_minVal);
			valueData[i] = m_histoValues[i];

			//import color for the current bin
			if (colorScheme != USE_SOLID_COLOR)
			{
				const ColorCompType* col = 0;
				if (colorScheme == USE_SF_SCALE)
				{
					//equivalent SF value
					assert(m_associatedSF);
					col = m_associatedSF->getColor(static_cast<ScalarType>(keyData[i]));
				}
				else if (colorScheme == USE_CUSTOM_COLOR_SCALE)
				{
					//use default gradient
					assert(colorScale);
					col = colorScale->getColorByRelativePos(normVal);
				}
				if (!col) //hidden values may have no associated color!
					col = ccColor::lightGrey.rgba;
				colors[i] = QColor(col[0],col[1],col[2]);
			}
		}

		if (!colors.isEmpty())
			m_histogram->setData(keyData, valueData, colors);
		else
			m_histogram->setData(keyData, valueData);
	}

	//overlay curve?
	int curveSize = static_cast<int>(m_curveValues.size());
	if (curveSize > 1)
	{
		QVector<double> x(curveSize), y(curveSize);
		
		double step = (m_maxVal - m_minVal) / (curveSize-1);
		for (int i=0; i<curveSize; ++i)
		{
			x[i] = m_minVal + (static_cast<double>(i)/*+0.5*/) * step;
			y[i] = m_curveValues[i];
		}

		// create graph and assign data to it:
		m_overlayCurve = addGraph();
		m_overlayCurve->setData(x, y);
		m_overlayCurve->setName("OverlayCurve");

		//set pen color
		const ccColor::Rgba& col = ccColor::darkGrey;
		QPen pen(QColor(col.r,col.g,col.b));
		m_overlayCurve->setPen(pen);

		//set width
		updateOverlayCurveWidth(rect().width(),rect().height());
	}
	
	//sf interaction mode
	if (m_sfInteractionMode && m_associatedSF)
	{
		const ccScalarField::Range& dispRange = m_associatedSF->displayRange();

		m_areaLeft = new QCPHiddenArea(true,xAxis, yAxis);
		m_areaLeft->setRange(dispRange.min(),dispRange.max());
		m_areaLeft->setCurrentVal(dispRange.start());
		addPlottable(m_areaLeft);

		m_areaRight = new QCPHiddenArea(false,xAxis, yAxis);
		m_areaRight->setRange(dispRange.min(),dispRange.max());
		m_areaRight->setCurrentVal(dispRange.stop());
		addPlottable(m_areaRight);

		const ccScalarField::Range& satRange = m_associatedSF->saturationRange();

		m_arrowLeft = new QCPArrow(xAxis, yAxis);
		m_arrowLeft->setRange(satRange.min(),satRange.max());
		m_arrowLeft->setCurrentVal(satRange.start());
		if (colorScale)
		{
			const ColorCompType* col = colorScale->getColorByRelativePos(m_associatedSF->symmetricalScale() ? 0.5 : 0,m_associatedSF->getColorRampSteps());
			if (col)
				m_arrowLeft->setColor(col[0],col[1],col[2]);
		}
		addPlottable(m_arrowLeft);

		m_arrowRight = new QCPArrow(xAxis, yAxis);
		m_arrowRight->setRange(satRange.min(),satRange.max());
		m_arrowRight->setCurrentVal(satRange.stop());
		if (colorScale)
		{
			const ColorCompType* col = colorScale->getColorByRelativePos(1.0,m_associatedSF->getColorRampSteps());
			if (col)
				m_arrowRight->setColor(col[0],col[1],col[2]);
		}
		addPlottable(m_arrowRight);
	}
	else if (m_drawVerticalIndicator) //vertical hint
	{
		m_vertBar = new QCPBarsWithText(xAxis, yAxis);
		addPlottable(m_vertBar);
		
		// now we can modify properties of vertBar
		m_vertBar->setName("VertLine");
		m_vertBar->setWidth(0/*(m_maxVal - m_minVal) / histoSize*/);
		m_vertBar->setBrush(QBrush(Qt::red));
		m_vertBar->setPen(QPen(Qt::red));
		m_vertBar->setAntialiasedFill(false);
		QVector<double> keyData(1);
		QVector<double> valueData(1);

		//horizontal position
		keyData[0] = m_minVal + (m_maxVal-m_minVal) * m_verticalIndicatorPositionPercent;
		valueData[0] = m_maxHistoVal;

		m_vertBar->setData(keyData,valueData);

		//precision (same as color scale)
		int precision = static_cast<int>(ccGui::Parameters().displayedNumPrecision);
		unsigned bin = static_cast<unsigned>(m_verticalIndicatorPositionPercent * m_histoValues.size());
		QString valueStr = QString("bin %0").arg(bin);
		m_vertBar->setText(valueStr);
		valueStr = QString("< %0 %").arg(100.0*static_cast<double>(partialSum)/static_cast<double>(totalSum),0,'f',3);
		m_vertBar->appendText(valueStr);
		valueStr = QString("val = %0").arg(m_minVal+(m_maxVal-m_minVal)*m_verticalIndicatorPositionPercent,0,'f',precision);
		m_vertBar->appendText(valueStr);
		m_vertBar->setTextAlignment(m_verticalIndicatorPositionPercent > 0.5);
	}

	//rescaleAxes();

	// redraw
	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);
}