QCustomPlot库画曲线时坐标轴范围自适应优化

本文介绍了在使用QCustomPlot库绘制实时曲线时遇到的问题,如坐标轴重叠和边缘坐标点被覆盖。作者提供了两种解决方案,一是调整坐标轴范围,二是修改QCustomPlot源代码中的rescale函数,确保曲线显示更加合理且避免直线被完全覆盖。
摘要由CSDN通过智能技术生成

QCustomPlot库画实时曲线自适应优化

为什么要优化

用Qt编写画图曲线时,一般有多种方式,这里主要介绍的是第三方库QCustomPlot来画2D实时曲线,而用这个库画2D实时曲线时,我们一般会用xAxis->rescale()或yAxis->rescale()或者customplot->rescaleAxes()这三个函数来让坐标轴自适应曲线的上下限值,但是有两个问题:
1、特殊直线会和坐标轴重合,被坐标轴覆盖。比如,存在两条直线y=0和y=10。
2、靠近坐标轴边缘位置的坐标点会被覆盖。 比如,存在两条直线y=0和y=10,(0,0)和(0,10)都在坐标轴上,不方便观察。
看起来感觉曲线就没留余地。
两条曲线只有一条能看到,y=0的曲线被x轴覆盖了
两条直线只有一条能看到,y=0的曲线被x轴覆盖了,y=10这条线太靠顶边了。

第一种改法(该方法不好)

直接在修改X轴Y轴的范围:

QCPRange rr= ui->ref_graphics->yAxis->range();
    double gap = rr.size();
    rr.lower = rr.lower - gap * 0.05;
    rr.upper = rr.upper + gap * 0.05;
    ui->ref_graphics->yAxis->setRange(rr);
    rr = ui->ref_graphics->xAxis->range();
    gap = rr.size();
    rr.lower = rr.lower - gap * 0.05;
    rr.upper = rr.upper + gap * 0.05;
    ui->ref_graphics->xAxis->setRange(rr);
    ui->ref_graphics->replot();

曲线在变化时,看起来没问题,但是如果只有一条直线时,Y轴的上下限会一直放大。

第二种方案,直接改QCustomPlot.cpp文件代码,完美解决。

找到这个函数:void QCPAxis::rescale(bool onlyVisiblePlottables)
它这个函数的逻辑是:找出窗口里面所有曲线值的上限和下限,然后大范围覆盖小范围,小范围扩展大范围。最后检查一下这个范围是不是大于0或者异常数据,处理这些异常情况后,把坐标轴的上下限修改一下。
这函数有两个情况没考虑:
1、就用曲线的极限值来当做坐标轴显示的极限值,就出现我们上面的情况,太极限了,一般肯定要留个一定的上下限空间比较合理。
2、当是一个直线时,即上下限范围=0,这个情况它认为是异常,直接用默认值处理。

那我们要改就要从这两方面去考虑。直接上代码:


void QCPAxis::rescale(bool onlyVisiblePlottables)
{
  QCPRange newRange;
  bool haveRange = false;
  double maxRangeSize = 0, maxRangeSizeTmp = 0;
  foreach (QCPAbstractPlottable *plottable, plottables())
  {
    if (!plottable->realVisibility() && onlyVisiblePlottables)
      continue;
    QCPRange plottableRange;
    bool currentFoundRange;
    QCP::SignDomain signDomain = QCP::sdBoth;
    if (mScaleType == stLogarithmic)
      signDomain = (mRange.upper < 0 ? QCP::sdNegative : QCP::sdPositive);
	if (plottable->keyAxis() == this)
	{
		plottableRange = plottable->getKeyRange(currentFoundRange, signDomain);
	}
	else
	{
		plottableRange = plottable->getValueRange(currentFoundRange, signDomain);
	}
	if (plottableRange.size() > 0) 
	{
		maxRangeSizeTmp = plottableRange.size() / 50;
	}
	else 
	{
		if (plottableRange.size() == 0) 
		{
			if (qFuzzyIsNull(plottableRange.upper)) 
			{ 
				maxRangeSizeTmp = 1; 
			}
			else 
			{
				maxRangeSizeTmp = abs(plottableRange.upper) / 50;
			}
		}
		else 
		{
			maxRangeSizeTmp = 1;
		}
	}
	if (maxRangeSize < maxRangeSizeTmp)
	{
		maxRangeSize = maxRangeSizeTmp;
	}
	if (currentFoundRange)
    {
		if (!haveRange) 
		{
			newRange = plottableRange;
		}
		else
		{
			newRange.expand(plottableRange);
		}
		haveRange = true;
    }
  }
  if (haveRange)
  {
    if (!QCPRange::validRange(newRange)) // likely due to range being zero (plottable has only constant data in this axis dimension), shift current range to at least center the plottable
    {
		double center = (newRange.lower+newRange.upper)*0.5; // upper and lower should be equal anyway, but just to make sure, incase validRange returned false for other reason
		if (mScaleType == stLinear)
		{
			//newRange.lower = center - mRange.size() / 2;
			//newRange.upper = center + mRange.size() / 2;
			newRange.lower = center - maxRangeSize;
			newRange.upper = center + maxRangeSize;
		} 
		else // mScaleType == stLogarithmic
		{
			newRange.lower = center / qSqrt(mRange.upper / mRange.lower);
			newRange.upper = center * qSqrt(mRange.upper / mRange.lower);
		}
    }
	else 
	{
		newRange.lower = newRange.lower - newRange.size() / 50;
		newRange.upper = newRange.upper + newRange.size() / 50;
	}
	setRange(newRange);
  }
}

当newRange的范围>0时,直接扩大2% ;
当newRange的范围=0时,直线是0时,范围取[-1, 1];直线是一个不为0的值a时,a 扩大2%;
当newRange的范围<0时,也范围取[-1, 1];
这结果同时对x轴和y轴都适用。
结果如下:看着舒服多了。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值