Logo Search packages:      
Sourcecode: qtiplot version File versions  Download package

PlotCurve.cpp

/***************************************************************************
    File                 : DataCurve.cpp
    Project              : QtiPlot
    --------------------------------------------------------------------
    Copyright            : (C) 2007 by Ion Vasilief
    Email (use @ for *)  : ion_vasilief*yahoo.fr
    Description          : AbstractPlotCurve and DataCurve classes

 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *  This program is free software; you can redistribute it and/or modify   *
 *  it under the terms of the GNU General Public License as published by   *
 *  the Free Software Foundation; either version 2 of the License, or      *
 *  (at your option) any later version.                                    *
 *                                                                         *
 *  This program is distributed in the hope that it will be useful,        *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
 *  GNU General Public License for more details.                           *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the Free Software           *
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor,                    *
 *   Boston, MA  02110-1301  USA                                           *
 *                                                                         *
 ***************************************************************************/
#include "PlotCurve.h"
#include "ScaleDraw.h"
#include <QDateTime>
#include <QMessageBox>
#include <QPainter>
#include <qwt_symbol.h>

DataCurve::DataCurve(Table *t, const QString& xColName, const QString& name, int startRow, int endRow):
    PlotCurve(name),
      d_table(t),
      d_x_column(xColName),
      d_start_row(startRow),
      d_end_row(endRow),
      d_labels_column(QString()),
      d_labels_color(Qt::black),
      d_labels_font(QFont()),
      d_labels_angle(0.0),
      d_white_out_labels(false),
      d_labels_align(Qt::AlignHCenter),
      d_labels_x_offset(0),
      d_labels_y_offset(50),
      d_selected_label(NULL)
{
      if (t && d_end_row < 0)
            d_end_row = t->numRows() - 1;
}

void DataCurve::setRowRange(int startRow, int endRow)
{
      if (d_start_row == startRow && d_end_row == endRow)
            return;

      d_start_row = startRow;
      d_end_row = endRow;

      loadData();

      foreach(DataCurve *c, d_error_bars)
            c->loadData();
}

void DataCurve::setFullRange()
{
      d_start_row = 0;
      d_end_row = d_table->numRows() - 1;

      loadData();

      foreach(DataCurve *c, d_error_bars)
            c->loadData();
}

bool DataCurve::isFullRange()
{
      if (d_start_row != 0 || d_end_row != d_table->numRows() - 1)
            return false;
      else
            return true;
}

QString DataCurve::plotAssociation()
{
      QString s = title().text();
    if (!d_x_column.isEmpty())
        s = d_x_column + "(X)," + title().text() + "(Y)";

    if (!d_labels_column.isEmpty())
        s += "," + d_labels_column + "(L)";

      return s;
}

void DataCurve::updateColumnNames(const QString& oldName, const QString& newName, bool updateTableName)
{
    if (updateTableName){
        QString s = title().text();
        QStringList lst = s.split("_", QString::SkipEmptyParts);
        if (lst[0] == oldName)
            setTitle(newName + "_" + lst[1]);

        if (!d_x_column.isEmpty()){
            lst = d_x_column.split("_", QString::SkipEmptyParts);
            if (lst[0] == oldName)
                d_x_column = newName + "_" + lst[1];
        }
    } else {
        if (title().text() == oldName)
            setTitle(newName);
        if (d_x_column == oldName)
            d_x_column = newName;
    }
}

bool DataCurve::updateData(Table *t, const QString& colName)
{
      if (d_table != t ||
       (colName != title().text() &&
       colName != d_x_column &&
       colName != d_labels_column))
        return false;

      loadData();
      return true;
}

void DataCurve::loadData()
{
      Graph *g = (Graph *)plot()->parent();
      if (!g)
            return;

      int xcol = d_table->colIndex(d_x_column);
      int ycol = d_table->colIndex(title().text());

      if (xcol < 0 || ycol < 0){
            remove();
            return;
      }

      int r = abs(d_end_row - d_start_row) + 1;
    QVarLengthArray<double> X(r), Y(r);
      int xColType = d_table->columnType(xcol);
      int yColType = d_table->columnType(ycol);

      QStringList xLabels, yLabels;// store text labels

      QTime time0;
      QDate date0;
      QString date_time_fmt = d_table->columnFormat(xcol);
      if (xColType == Table::Time){
            for (int i = d_start_row; i <= d_end_row; i++ ){
                  QString xval=d_table->text(i,xcol);
                  if (!xval.isEmpty()){
                        time0 = QTime::fromString (xval, date_time_fmt);
                        if (time0.isValid())
                              break;
                  }
            }
      } else if (xColType == Table::Date){
            for (int i = d_start_row; i <= d_end_row; i++ ){
                  QString xval=d_table->text(i,xcol);
                  if (!xval.isEmpty()){
                        date0 = QDate::fromString (xval, date_time_fmt);
                        if (date0.isValid())
                              break;
                  }
            }
      }

      int size = 0;
      for (int i = d_start_row; i <= d_end_row; i++ ){
            QString xval = d_table->text(i,xcol);
            QString yval = d_table->text(i,ycol);
            if (!xval.isEmpty() && !yval.isEmpty()){
                bool valid_data = true;
                  if (xColType == Table::Text){
                        xLabels << xval;
                        X[size] = (double)(size + 1);
                  } else if (xColType == Table::Time){
                        QTime time = QTime::fromString (xval, date_time_fmt);
                        if (time.isValid())
                              X[size]= time0.msecsTo (time);
                  } else if (xColType == Table::Date){
                        QDate d = QDate::fromString (xval, date_time_fmt);
                        if (d.isValid())
                              X[size] = (double) date0.daysTo(d);
                  } else
                        X[size] = ((Plot *)plot())->locale().toDouble(xval, &valid_data);

                  if (yColType == Table::Text){
                        yLabels << yval;
                        Y[size] = (double)(size + 1);
                  } else
                        Y[size] = ((Plot *)plot())->locale().toDouble(yval, &valid_data);

            if (valid_data)
                size++;
            }
      }

    X.resize(size);
    Y.resize(size);

      if (!size){
            remove();
            return;
      } else {
            if (d_type == Graph::HorizontalBars){
                  setData(Y.data(), X.data(), size);
                  foreach(DataCurve *c, d_error_bars)
                c->setData(Y.data(), X.data(), size);
            } else {
                  setData(X.data(), Y.data(), size);
                  foreach(DataCurve *c, d_error_bars)
                c->setData(X.data(), Y.data(), size);
            }

            if (xColType == Table::Text){
                  if (d_type == Graph::HorizontalBars)
                        g->setLabelsTextFormat(QwtPlot::yLeft, Graph::Txt, d_x_column, xLabels);
                  else
                g->setLabelsTextFormat(QwtPlot::xBottom, Graph::Txt, d_x_column, xLabels);
            } else if (xColType == Table::Time ){
                  if (d_type == Graph::HorizontalBars){
                        QStringList lst = g->axisFormatInfo(QwtPlot::yLeft).split(";");
                        QString fmtInfo = time0.toString() + ";" + lst[1];
                        g->setLabelsDateTimeFormat(QwtPlot::yLeft, Graph::Time, fmtInfo);
                  } else {
                        QStringList lst = g->axisFormatInfo(QwtPlot::xBottom).split(";");
                        QString fmtInfo = time0.toString() + ";" + lst[1];
                        g->setLabelsDateTimeFormat(QwtPlot::xBottom, Graph::Time, fmtInfo);
                  }
            } else if (xColType == Table::Date ) {
                  if (d_type == Graph::HorizontalBars){
                        QStringList lst = g->axisFormatInfo(QwtPlot::yLeft).split(";");
                        QString fmtInfo = date0.toString(Qt::ISODate) + ";" + lst[1];
                        g->setLabelsDateTimeFormat(QwtPlot::yLeft, Graph::Date, fmtInfo);
                  } else {
                        QStringList lst = g->axisFormatInfo(QwtPlot::xBottom).split(";");
                        QString fmtInfo = date0.toString(Qt::ISODate) + ";" + lst[1];
                        g->setLabelsDateTimeFormat(QwtPlot::xBottom, Graph::Date, fmtInfo);
                  }
            }

            if (yColType == Table::Text)
            g->setLabelsTextFormat(QwtPlot::yLeft, Graph::Txt, title().text(), yLabels);
      }

    if (!d_labels_list.isEmpty()){
        ((Graph*)plot()->parent())->updatePlot();
        loadLabels();
    }
}

void DataCurve::removeErrorBars(DataCurve *c)
{
      if (!c || d_error_bars.isEmpty())
            return;

      int index = d_error_bars.indexOf(c);
      if (index >= 0 && index < d_error_bars.size())
            d_error_bars.removeAt(index);
}

void DataCurve::clearErrorBars()
{
      if (d_error_bars.isEmpty())
            return;

      foreach(DataCurve *c, d_error_bars)
            c->remove();
}

void DataCurve::remove()
{
      Graph *g = (Graph *)plot()->parent();
      if (!g)
            return;

      g->removeCurve(title().text());
}

void DataCurve::setVisible(bool on)
{
      QwtPlotCurve::setVisible(on);
      foreach(DataCurve *c, d_error_bars)
            c->setVisible(on);
}

int DataCurve::tableRow(int point)
{
    if (!d_table)
        return -1;

      int xcol = d_table->colIndex(d_x_column);
      int ycol = d_table->colIndex(title().text());

      if (xcol < 0 || ycol < 0)
            return -1;

    int xColType = d_table->columnType(xcol);
    if (xColType == Table::Date){
        QString format = d_table->columnFormat(xcol);
        QDate date0 = QDate::fromString (d_table->text(d_start_row, xcol), format);
        for (int i = d_start_row; i <= d_end_row; i++ ){
            QDate d = QDate::fromString (d_table->text(i, xcol), format);
            if (d.isValid()){
                if (d_type == Graph::HorizontalBars && date0.daysTo(d) == y(point) && d_table->cell(i, ycol) == x(point))
                    return i;
                else if (date0.daysTo(d) == x(point) && d_table->cell(i, ycol) == y(point))
                    return i;
            }
        }
    } else if (xColType == Table::Time){
        QString format = d_table->columnFormat(xcol);
        QTime t0 = QTime::fromString (d_table->text(d_start_row, xcol), format);
        for (int i = d_start_row; i <= d_end_row; i++ ){
            QTime t = QTime::fromString (d_table->text(i, xcol), format);
            if (t.isValid()){
                if (d_type == Graph::HorizontalBars && t0.msecsTo(t) == y(point) && d_table->cell(i, ycol) == x(point))
                    return i;
                if (t0.msecsTo(t) == x(point) && d_table->cell(i, ycol) == y(point))
                    return i;
            }
        }
    }

      double x_val = x(point);
      double y_val = y(point);
      for (int i = d_start_row; i <= d_end_row; i++ ){
            if (d_table->cell(i, xcol) == x_val && d_table->cell(i, ycol) == y_val)
                  return i;
      }
      return -1;
}

void DataCurve::setLabelsColumnName(const QString& name)
{
      if (!validCurveType())
            return;

      if (d_labels_column == name && !d_labels_list.isEmpty())
            return;

      d_labels_column = name;
    loadLabels();
}

void DataCurve::loadLabels()
{
      if (!validCurveType())
            return;

    clearLabels();

    int xcol = d_table->colIndex(d_x_column);
    int ycol = d_table->colIndex(title().text());
    int labelsCol = d_table->colIndex(d_labels_column);
    int cols = d_table->numCols();
      if (xcol < 0 || ycol < 0 || labelsCol < 0 ||
        xcol >= cols || ycol >= cols || labelsCol >= cols)
            return;

      QwtPlot *d_plot = plot();
      if (!d_plot)
            return;

    int index = 0;
      for (int i = d_start_row; i <= d_end_row; i++){
            if (d_table->text(i, xcol).isEmpty() ||
            d_table->text(i, ycol).isEmpty())
            continue;

            PlotMarker *m = new PlotMarker(index, d_labels_angle);

            QwtText t = QwtText(d_table->text(i, labelsCol));
            t.setColor(d_labels_color);
            t.setFont(d_labels_font);
            if (d_white_out_labels)
                  t.setBackgroundBrush(QBrush(Qt::white));
        else
            t.setBackgroundBrush(QBrush(Qt::transparent));
            m->setLabel(t);

        int x_axis = xAxis();
        int y_axis = yAxis();
            m->setAxis(x_axis, y_axis);

            QSize size = t.textSize();
        int dx = int(d_labels_x_offset*0.01*size.height());
        int dy = -int((d_labels_y_offset*0.01 + 0.5)*size.height());
        int x2 = d_plot->transform(x_axis, x(index)) + dx;
        int y2 = d_plot->transform(y_axis, y(index)) + dy;
        switch(d_labels_align){
            case Qt::AlignLeft:
            break;
            case Qt::AlignHCenter:
                x2 -= size.width()/2;
            break;
            case Qt::AlignRight:
                x2 -= size.width();
            break;
        }
        m->setXValue(d_plot->invTransform(x_axis, x2));
        m->setYValue(d_plot->invTransform(y_axis, y2));
            m->attach(d_plot);
            d_labels_list << m;
            index++;
      }
}

void DataCurve::clearLabels()
{
      if (!validCurveType())
            return;

      foreach(PlotMarker *m, d_labels_list){
            m->detach();
            delete m;
      }
      d_labels_list.clear();
}

void DataCurve::setLabelsFont(const QFont& font)
{
      if (!validCurveType())
            return;

     if (font == d_labels_font)
        return;

    d_labels_font = font;

    foreach(PlotMarker *m, d_labels_list){
            QwtText t = m->label();
            t.setFont(font);
            m->setLabel(t);
      }
      updateLabelsPosition();
}

void DataCurve::setLabelsColor(const QColor& c)
{
      if (!validCurveType())
            return;

    if (c == d_labels_color)
        return;

    d_labels_color = c;

    foreach(PlotMarker *m, d_labels_list){
            QwtText t = m->label();
            t.setColor(c);
            m->setLabel(t);
      }
}

void DataCurve::setLabelsAlignment(int flags)
{
      if (!validCurveType())
            return;

    if (flags == d_labels_align)
        return;

    d_labels_align = flags;
    updateLabelsPosition();
}

void DataCurve::updateLabelsPosition()
{
      if (!validCurveType())
            return;

    QwtPlot *d_plot = plot();
    if (!d_plot)
        return;

    foreach(PlotMarker *m, d_labels_list){
        int index = m->index();
        QSize size = m->label().textSize();
        int x_axis = xAxis();
        int y_axis = yAxis();
        int dx = int(d_labels_x_offset*0.01*size.height());
        int dy = -int((d_labels_y_offset*0.01 + 0.5)*size.height());
        int x2 = d_plot->transform(x_axis, x(index)) + dx;
        int y2 = d_plot->transform(y_axis, y(index)) + dy;
        switch(d_labels_align){
            case Qt::AlignLeft:
            break;
            case Qt::AlignHCenter:
                x2 -= size.width()/2;
            break;
            case Qt::AlignRight:
                x2 -= size.width();
            break;
        }
        m->setXValue(d_plot->invTransform(x_axis, x2));
        m->setYValue(d_plot->invTransform(y_axis, y2));
      }
}

void DataCurve::setLabelsOffset(int x, int y)
{
      if (!validCurveType())
            return;

    if (x == d_labels_x_offset && y == d_labels_y_offset)
        return;

    d_labels_x_offset = x;
    d_labels_y_offset = y;
    updateLabelsPosition();
}

void DataCurve::setLabelsRotation(double angle)
{
      if (!validCurveType())
            return;

    if (angle == d_labels_angle)
        return;

    d_labels_angle = angle;

    foreach(PlotMarker *m, d_labels_list)
            m->setAngle(angle);
}

void DataCurve::setLabelsWhiteOut(bool whiteOut)
{
      if (!validCurveType())
            return;

    if (whiteOut == d_white_out_labels)
        return;

    d_white_out_labels = whiteOut;

    foreach(PlotMarker *m, d_labels_list){
            QwtText t = m->label();
            if (whiteOut)
                  t.setBackgroundBrush(QBrush(Qt::white));
        else
            t.setBackgroundBrush(QBrush(Qt::transparent));
            m->setLabel(t);
      }
}

void DataCurve::clone(DataCurve* c)
{
      if (!validCurveType())
            return;

    d_labels_color = c->labelsColor();
    d_labels_font = c->labelsFont();
      d_labels_angle = c->labelsRotation();
      d_white_out_labels = c->labelsWhiteOut();
      d_labels_align = c->labelsAlignment();
      d_labels_x_offset = c->labelsXOffset();
      d_labels_y_offset = c->labelsYOffset();

    if (!c->labelsColumnName().isEmpty()){
        plot()->replot();
        setLabelsColumnName(c->labelsColumnName());
    }
}

QString DataCurve::saveToString()
{
      if (!validCurveType())
            return QString();

    if (d_labels_list.isEmpty() || type() == Graph::Function || type() == Graph::Box)
        return QString();

    QString s = "<CurveLabels>\n";
    s += "\t<column>" + d_labels_column + "</column>\n";
    s += "\t<color>" + d_labels_color.name() + "</color>\n";
    s += "\t<whiteOut>" + QString::number(d_white_out_labels) + "</whiteOut>\n";
    s += "\t<font>" + d_labels_font.family() + "\t";
    s += QString::number(d_labels_font.pointSize()) + "\t";
    s += QString::number(d_labels_font.bold()) + "\t";
    s += QString::number(d_labels_font.italic()) + "\t";
    s += QString::number(d_labels_font.underline()) + "</font>\n";
    s += "\t<angle>" + QString::number(d_labels_angle) + "</angle>\n";
    s += "\t<justify>" + QString::number(d_labels_align) + "</justify>\n";
    if (d_labels_x_offset != 0.0)
        s += "\t<xoffset>" + QString::number(d_labels_x_offset) + "</xoffset>\n";
    if (d_labels_y_offset != 0.0)
        s += "\t<yoffset>" + QString::number(d_labels_y_offset) + "</yoffset>\n";
    return s + "</CurveLabels>\n";
}

bool DataCurve::selectedLabels(const QPoint& pos)
{
      if (!validCurveType())
            return false;
      
    QwtPlot *d_plot = plot();
    if (!d_plot)
        return false;

      
    bool selected = false;
      d_selected_label = NULL;
    foreach(PlotMarker *m, d_labels_list){
        int x = d_plot->transform(xAxis(), m->xValue());
        int y = d_plot->transform(yAxis(), m->yValue());
        if (QRect(QPoint(x, y), m->label().textSize()).contains(pos)){
                  d_selected_label = m;
                  d_click_pos_x = d_plot->invTransform(xAxis(), pos.x());
                  d_click_pos_y = d_plot->invTransform(yAxis(), pos.y());
            setLabelsSelected();
            return true;
        }
      }
      return selected;
}

bool DataCurve::hasSelectedLabels()
{
      if (!validCurveType())
            return false;

    if (d_labels_list.isEmpty())
        return false;

    foreach(PlotMarker *m, d_labels_list){
        if (m->label().backgroundPen() == QPen(Qt::blue))
            return true;
        else
            return false;
    }
    return false;
}

void DataCurve::setLabelsSelected(bool on)
{
      if (!validCurveType())
            return;

    foreach(PlotMarker *m, d_labels_list){
            QwtText t = m->label();
            if(t.text().isEmpty())
            continue;

        if (on){
            t.setBackgroundPen(QPen(Qt::blue));
        } else
            t.setBackgroundPen(QPen(Qt::NoPen));
        m->setLabel(t);
    }
    if (on){
        Graph *g = (Graph *)plot()->parent();
        g->selectTitle(false);
        g->deselectMarker();
        g->notifyFontChange(d_labels_font);
    }
    plot()->replot();
}

bool DataCurve::validCurveType()
{
      int style = type();
      if (style == Graph::Function || style == Graph::Box ||
            style == Graph::Pie || style == Graph::ErrorBars ||
            style == Graph::ColorMap ||  style == Graph::GrayScale ||
            style == Graph::Contour || style == Graph::ImagePlot)
            return false;
      return true;
}

void DataCurve::moveLabels(const QPoint& pos)
{
      if (!validCurveType())
            return;
      if (!d_selected_label || d_labels_list.isEmpty())
            return;

    QwtPlot *d_plot = plot();
    if (!d_plot)
        return;

    d_plot->replot();
    int d_x = pos.x() - d_plot->transform(xAxis(), d_click_pos_x);
      int d_y = pos.y() - d_plot->transform(yAxis(), d_click_pos_y);

      int height = d_selected_label->label().textSize().height();
      d_labels_x_offset += int(d_x*100.0/(double)height);
    d_labels_y_offset -= int(d_y*100.0/(double)height);

      updateLabelsPosition();
      d_plot->replot();

    ((Graph *)d_plot->parent())->notifyChanges();

      d_click_pos_x = d_plot->invTransform(xAxis(), pos.x());
      d_click_pos_y = d_plot->invTransform(yAxis(), pos.y());
}

QwtDoubleRect PlotCurve::boundingRect() const
{
    QwtDoubleRect r = QwtPlotCurve::boundingRect();
    if (symbol().style() == QwtSymbol::NoSymbol || dataSize() < 2)
        return r;

    int margin = 1;
    if (symbol().style() != QwtSymbol::NoSymbol)
        margin += symbol().size().width();

    const QwtScaleMap &xMap = plot()->canvasMap(xAxis());
      const QwtScaleMap &yMap = plot()->canvasMap(yAxis());

    int x_right = xMap.transform(r.right());
    double d_x_right = xMap.invTransform(x_right + margin);
    int x_left = xMap.transform(r.left());
    double d_x_left = xMap.invTransform(x_left - margin);

    int y_top = yMap.transform(r.top());
    double d_y_top = yMap.invTransform(y_top + margin);
    int y_bottom = yMap.transform(r.bottom());
    double d_y_bottom = yMap.invTransform(y_bottom - margin);

    return QwtDoubleRect(d_x_left, d_y_top, qAbs(d_x_right - d_x_left), qAbs(d_y_bottom - d_y_top));
}

PlotMarker::PlotMarker(int index, double angle):QwtPlotMarker(),
      d_index(index),
      d_angle(angle)
{}

void PlotMarker::draw(QPainter *p, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRect &) const
{
      p->save();
      int x = xMap.transform (xValue());
      int y = yMap.transform (yValue());

      p->translate(x, y);
      p->rotate(-d_angle);

      QwtText text = label();
      text.draw(p, QRect(QPoint(0, 0), text.textSize()));
      p->restore();
}

Generated by  Doxygen 1.6.0   Back to index