QCustomPlot Discussion and Comments

is it possible to add multicolor graphReturn to overview

I added graph

ui->widget->addGraph(ui->widget->xAxis, ui->widget->yAxis);
ui->widget->graph(1)->setData(xVector, yVector);

and set color for it:

ui->widget->graph(1)->setPen(QPen(Qt::red));

is it possible to set multi color for graph?
For example red from 0 to 10 and blue from 10 to 30 and ...

As far as I know you can only set the pen (and the color) used to draw the single plots, you cannot set multiple colors/pens to a plot.

That would be a nice feature to be added to QCP.

If you really want this feature quickly, just inherit QCPGraph to your own class like MyQCPGraph and then overload the draw() virtual function. Requires a small amount of effort, but easily done. You could then pass an array containing the pen colours you want for each data point using your new class.

I have done something similar for contouring. I used QCPAbstractPlottable() to draw a contour plot. Each contour line of the plot can have a different colour depending on its contour value if the user chooses.

thank you for your answer sdhengsoft. But I don not understand passing array.
I can create an array and fill with colors but How can I determine color of x-values. For example Array has blue, red, green but in which x values?

Ahhh! Sorry I misunderstood what your values of 0 to 10 were. I thought they were data points 0 through 10. But you mean that these are X values or Y values 0 through 10.

In this case you want to define a function that based on the input value a colour is returned. I do this for contour plotting, but I use a linear colour map. In your case you want a discrete colour map based on input value. So in my code when I want to draw a line I do this:

colourMap = QCPLinearColorMap; // My colour stops are defined as values 0.0 through 1.0.
colourMap.addColorStop( 0.0, Qt::red);
colourMap.addColorStop( 0.1, Qt::blue);
colourMap.addColorStop( 0.3, Qt::green);
...
...
QPen pen;
pen.setColor( colourMap.color( 0.0, 100.0, xValue)); // Set colour range 0 to 100.0.
// Draw somthing.

The code I use for the linear colour map is below. You just need to modify it to do discrete colour changes rather than linear (basically delete some of my code).


class QCPLinearColorMap
{
public:
  QCPLinearColorMap() {}
  ~QCPLinearColorMap() {}

  void addColorStop( const double &value, const QColor &color);
  QColor color( const double &vMin, const double &vMax, const double value);

private:
  struct ColorStop {
    ColorStop( const double &v, const QColor &c) : value( v), color( c) {}
    double value;
    QColor color;
  };

  QList< ColorStop > colorStops_;
};

void QCPLinearColorMap::addColorStop( const double &value, const QColor &color)
{
  colorStops_ << ColorStop( value, color);
}

QColor QCPLinearColorMap::color( const double &vMin, const double &vMax, const double value)
{
  if ( colorStops_.isEmpty()) {
    return QColor();
  }
  if ( colorStops_.count() == 1) {
    return colorStops_[0].color;
  }

  // Normalise value between 0 < x < 1.
  double x = ( value - vMin) / ( vMax - vMin);
  if ( x <= colorStops_.first().value) {
    return colorStops_.first().color;
  }
  if ( x >= colorStops_.last().value) {
    return colorStops_.last().color;
  }

  // Using linear search for closest colour stops rather than mid-point search.
  // It is unlikely there would be a large number of colour stops.
  int i = 0;
  while ( i < colorStops_.count() - 2 && x > colorStops_[i+1].value) {
    ++i;
  }

  // Interpolate between closest colour stops.
  ColorStop &c1 = colorStops_[i];
  ColorStop &c2 = colorStops_[i+1];
  double dx = c2.value - c1.value;
  double r1 = ( c2.value - x) / dx;
  double r2 = ( x - c1.value) / dx;

  int r = r1 * c1.color.red()   + r2 * c2.color.red();
  int g = r1 * c1.color.green() + r2 * c2.color.green();
  int b = r1 * c1.color.blue()  + r2 * c2.color.blue();

  return QColor( r, g, b);
}

I hope this is not too complicated. Have Fun !

Thank you for your answer. I use your code but still all graph has same color. This picture [http://imgur.com/8t0BoQT] shows what I want to do. Do I misuse your code?

I think I'd need to see your overload of the virtual draw() code to figure out why your colours are not changing. Are you able to post the example here?

Actually I can not overloaded draw() function. Just I set QColor (which your color function returns) as parameter in setPen(QPen) function.

Ahh. You need to create your own QCPGraph class and overload the draw() function and do the drawing yourself with the colours you want to use. There is no simple method of setting the multi-colours that I'm aware of.

class MyGraph : public QCPGraph
{
public:
  MyGraph(QCPAxis *keyAxis, QCPAxis *valueAxis) : QCPGraph( keyAxis, valueAxis) {}
  virtual ~MyGraph() {}

protected:
  virtual draw( QCPPainter *painter) {
    // Draw your stuff here based on code in QCPGraph::draw().
  };
}

If I want to plot multiple curves, each curve with different color, what should I do? Thanks.

Have the same task.. can anyone tell, write few line example - what and how exactly should be overloaded draw() function?
here is code I suppose which should be modified somehow..

  
void QCPGraph::draw(QCPPainter *painter) {
....
// draw fill of graph:
  if (mLineStyle != lsNone)
    drawFill(painter, lineData);
  
  // draw line:
  if (mLineStyle == lsImpulse)
    drawImpulsePlot(painter, lineData);
  else if (mLineStyle != lsNone)
    drawLinePlot(painter, lineData); // also step plots can be drawn as a line plot
  
  // draw scatters:
  if (scatterData)
    drawScatterPlot(painter, scatterData);
.... 
}

it isnt the draw function you want to overload, it is the drawFill,drawLinePlot functions. at the top of each function it normally sets the painter's brush and pen. you would want to put that just before it actually calls the painter function to draw something to the canvas.

Does someone have try those solution ? Are they great and not to hard to do?

hi

Anyone can give a definitive example on how to draw a multi-colored scattered plot based on the scalar values assigned to the scatter points? Basically, I want to draw a set of scatters in the form of (x, y, value), and the color the each scatter is based on value. Thanks.

You can use the following class to solve that problem.
QCPColorCurve.h:

class QCPColorCurve : public QCPCurve
{
public:
    QCPColorCurve(QCPAxis *keyAxis, QCPAxis *valueAxis);
    virtual ~QCPColorCurve();
    void setData(const QVector<double> & keys, const QVector<double> & values, const QVector<QColor> & colors);
protected:
    virtual void drawScatterPlot(QCPPainter *painter, const QVector<QPointF> &points, const QCPScatterStyle &style) const;
private:
    QVector<QColor> colors_;
};

QCPColorCurve.cpp
#include "QCPColorCurve.h"

QCPColorCurve::QCPColorCurve(QCPAxis *keyAxis, QCPAxis *valueAxis) : QCPCurve(keyAxis, valueAxis) {}

QCPColorCurve::~QCPColorCurve(){ }

void QCPColorCurve::setData(const QVector<double> & keys, const QVector<double> & values, const QVector<QColor> & colors){
    if (values.size() != colors.size()) return;
    colors_ = colors;
    QCPCurve::setData(keys, values);
}

void QCPColorCurve::drawScatterPlot(QCPPainter * painter, const QVector<QPointF> & points, const QCPScatterStyle & style) const {
    applyScattersAntialiasingHint(painter);
    int nPoints = points.size();
    for (int i = 0; i < nPoints; ++i)
        if (!qIsNaN(points.at(i).x()) && !qIsNaN(points.at(i).y())){
            painter->setPen(colors_[i]);
            style.drawShape(painter, points.at(i));
        }
}

Hello. I am hoping that there are some updates regarding this matter. I am like most others struggling with this. It would be very cool to be able to do different colors for different Y values..
I currently use the following functions to update my graph:

void MainWindow::addPoint(double x, double y)
{
    qv_x.append(x);
    qv_y.append(y);

}

void MainWindow::plot(QCustomPlot *customPlot)
{
    customPlot->graph(0)->setData(qv_x,qv_y);
    customPlot->replot();
    customPlot->update();

}


The functions are being called every second so my plot updates nicely every second. I need to change above methods to do the following logic:

if Y value < 10, do green color
if Y value >10 and <100, do orange color
if Y value >100, do red color

Someone in this forum thread suggsted overloading draw(), drawScatterPlot() and other methods but as you can see I do not use those methods. Is that an issue?

Maybe someone know a simple way to achieve what I want?

Can't you just have 3 graphs using different pen colors, and when a new point comes in, add it to the appropriate graph based on y value?

If you're drawing lines from point to point, a 4th graph with all the data that doesn't include plot symbols will be needed.

If you want lines that change color when they cross the 10 or 100 boundaries, you'll need to generate fake data at the crossing points and have graphs for each color.

I guess that could work but in my particular case, that causes unnecessary issues. Some other features that I use are being able to select a graph or part of it and calculate average. If my plot will consist of multiple graphs instead of just 1 graph that will overcomplicate everything else for me.

Same requirement here , any out of the box solutions available ?