QCustomPlot Discussion and Comments

QCPColorMap spectrogramReturn to overview

The QCPColorMap can already be used to create nice-looking spectrograms, but it requires some tedious work like shifting all existing data before inserting next line/row. Perhaps a lineOffset field could be added to QCPColorMapData and updateMapImage() modified from

    for (int line=0; line<lineCount; ++line)
    {
      QRgb* pixels = reinterpret_cast<QRgb*>(mMapImage.scanLine(lineCount-1-line));
      mGradient.colorize(rawData+line*rowCount, mDataRange, pixels, rowCount, 1, mDataScaleType==QCPAxis::stLogarithmic);
    }
to
    for (int line=mMapData->lineOffset; line<lineCount; ++line)
    {
      QRgb* pixels = reinterpret_cast<QRgb*>(mMapImage.scanLine(lineCount-1-(line-mMapData->lineOffset)));
      mGradient.colorize(rawData+line*rowCount, mDataRange, pixels, rowCount, 1, mDataScaleType==QCPAxis::stLogarithmic);
    }
    for (int line=0; line<mMapData->lineOffset; ++line)
    {
      QRgb* pixels = reinterpret_cast<QRgb*>(mMapImage.scanLine(lineCount-1-(line +lineCount-mMapData->lineOffset)));
      mGradient.colorize(rawData+line*rowCount, mDataRange, pixels, rowCount, 1, mDataScaleType==QCPAxis::stLogarithmic);
    }

and data/cell getters/setters changed to
double QCPColorMapData::data(double key, double value)
{
  int keyCell = (key-mKeyRange.lower)/(mKeyRange.upper-mKeyRange.lower)*(mKeySize-1)+0.5;
  int valueCell = (1.0-(value-mValueRange.lower)/(mValueRange.upper-mValueRange.lower))*(mValueSize-1)+0.5;
  valueCell = (valueCell + lineOffset)%valueSize();
  if (keyCell >= 0 && keyCell < mKeySize && valueCell >= 0 && valueCell < mValueSize)
    return mData[valueCell*mKeySize + keyCell];
  else
    return 0;
}

double QCPColorMapData::cell(int keyIndex, int valueIndex)
{
  if (keyIndex >= 0 && keyIndex < mKeySize && valueIndex >= 0 && valueIndex < mValueSize)
  {
    valueIndex = (valueIndex + lineOffset)%valueSize();
    return mData[valueIndex*mKeySize + keyIndex];
  }
  else
    return 0;
}

void QCPColorMapData::setData(double key, double value, double z)
{
  int keyCell = (key-mKeyRange.lower)/(mKeyRange.upper-mKeyRange.lower)*(mKeySize-1)+0.5;
  int valueCell = (value-mValueRange.lower)/(mValueRange.upper-mValueRange.lower)*(mValueSize-1)+0.5;

  valueCell = (valueCell + lineOffset)%valueSize();
  if (keyCell >= 0 && keyCell < mKeySize && valueCell >= 0 && valueCell < mValueSize)
  {
    mData[valueCell*mKeySize + keyCell] = z;
    if (z < mDataBounds.lower)
      mDataBounds.lower = z;
    if (z > mDataBounds.upper)
      mDataBounds.upper = z;
     mDataModified = true;
  }
}

void QCPColorMapData::setCell(int keyIndex, int valueIndex, double z)
{
  if (keyIndex >= 0 && keyIndex < mKeySize && valueIndex >= 0 && valueIndex < mValueSize)
  {
      valueIndex = (valueIndex + lineOffset)%valueSize();

    mData[valueIndex*mKeySize + keyIndex] = z;
    if (z < mDataBounds.lower)
      mDataBounds.lower = z;
    if (z > mDataBounds.upper)
      mDataBounds.upper = z;
     mDataModified = true;
  }
}

Some helper functions like

void QCPColorMapData::shift(bool down)
{
    if(down)
        lineOffset = ++lineOffset%valueSize();
    else
        lineOffset = (--lineOffset +valueSize())%valueSize();
    mDataModified = true;
}

and
void QCPColorMapData::insertValues(QVector<double> values, bool top)
{
    shift(top);
    for(int i = 0; i < values.size(); ++i)
        setCell(i, top?mValueSize-1:0, values[i]);
}

could then easily be introduced.

Oh Thanks, It's exactly what I am looking for! It could be cool to have a setData function that takes QVector<QVector<double>> too. I don't know if it's doable...

Thanks again!

Thank Henrik,

I am implemented as you described and it is working amazingly good.

Thank you

Hi Henrik and thanks a lot.

It works perfectly and without additional CPU usage. Congratulation ;).
But can you propose a code version to shift and insert values by row and not by line (as it was described in our post).

Thank you

(Not see that the first post was to old :( )

Hi all,

First of all thanks Henrik, this code still works absolutely fine and runs very efficiently. I made a few modifications to get exactly what I needed but I am wondering if anyone has modified this code to stream from the left to the right side of the canvas?
If anyone has done it would save me a lot of time, if not I will work on how to do it and will post the outcomes.

Best Regards, Ren

Hi there, Any body has a code for this changes?

Hello, according to the above method, the rapid update of the Y-axis direction can be achieved, so how to achieve the X-axis direction?