Вывод графиков в Qt 5 при помощи QCustomPlot

Опубликовано lamazavr - вс, 02/09/2014 - 12:12
Body

Одной из распространенных задач программирования является - построение графиков.
Вы конечно можете создать новый проект и используя библиотеки вроде freeglut набросать программку для отрисовки графика, но зачем заниматься изобретением велосипеда? Зачем рисовать оси самостоятельно, если это можно сделать одной строкой при помощи библиотеки, которая не особо то и раздуем ваш код.

Мой выбор для таких вещей - QCustomPlot. Это библиотека для Qt.

Прежде всего скачайте библиотеку с сайта QCustomPlot. Там всего два файла, которые нужно добавить к проекту.
Я просто создаю новый проект Qt и ложу их в папку с исходниками, после чего нажимаю правой клавишей по проекту -- Добавить существующие файлы и выбираю qcustomplot.h и qcustomplot.cpp.

Теперь идем в настройки проекта (pro файл).
Тут нужно добавить

QT       += printsupport

А также, проконтролировать появились ли добавленные файлы в SOURCES и HEADERS.

Теперь переходим к редактированию формы.

Добавляем QWidget и нажав по нем правой клавишей мыши -- Преобразовать в, преобразовываем в QCustomPlot

Можно собрать. Вы увидите оси координат.

Теперь давайте "нарисем" синусоиду.
Для этого заинклудте math.h, мы будем использовать число пи и функцию синуса из этой библиотеки.

Добавим в конструктор окна такой код:

    // генерируем данные
    QVector<double> x(360), y(360); // строить будем до 360 градусов
    for (int i=0; i<360; ++i)
    {
      x[i] = i;
      y[i] = 10*sin(x[i]*M_PI/180); // вычисляем синус
    }
    // создаем график и добавляем данные:
    ui->widget->addGraph();
    ui->widget->graph(0)->setData(x, y);
    // задаем имена осей координат
    ui->widget->xAxis->setLabel("x");
    ui->widget->yAxis->setLabel("y");
    // задаем размеры осей
    ui->widget->xAxis->setRange(0, 360);
    ui->widget->yAxis->setRange(-10, 10);
    ui->widget->replot();

После компиляции вы увидите результат:

Все классно! Да вот подписи на осях нам не сильно подходят. Я хочу чтобы шаг был 30 градусов.
В принципе для этого достаточно изменить вектор TickVector.

    QVector<double> Ticks;  // вектор с шагом в 30 градусов
    int i = 0;
    while(i<=360) {
        Ticks << i;
        i+=30;
    }
    ui->widget->xAxis->setAutoTicks(false); // выключаем автоматические отсчеты
    ui->widget->xAxis->setTickVector(Ticks);  // задаем созданный нами вектор

После этого вы увидите такие оси:

Но мы зайдем немного дальше и изменим градусы на доли числа Пи.
Для этого необходимо сформировать вектор TickVectorLabels из QString.
С этим массивом все не так просто. Пришлось заполнить его вручную.

    QVector<QString> Labels;
    Labels << "0" << QString::fromUtf8("π/6") << QString::fromUtf8("π/3")
           << QString::fromUtf8("π/2") << QString::fromUtf8("2π/3")
           << QString::fromUtf8("5π/6") << QString::fromUtf8("π")
           << QString::fromUtf8("7π/6") << QString::fromUtf8("4π/3")
           << QString::fromUtf8("3π/2") << QString::fromUtf8("5π/3")
           << QString::fromUtf8("11π/6") << QString::fromUtf8("2π");

    ui->widget->xAxis->setAutoTickLabels(false);
    ui->widget->xAxis->setTickVectorLabels(Labels);

Вот как это выглядит:

Как видите все получилось ;) Успехов в построении графиков.

Комментарии

вместо "Для этого заинклудте math.h, мы будем использовать число пи и функцию синуса из этой библиотеки."
можно включить в mainwindow.h строку:
#include <qmath.h>

Пожалуйста расскажите подробно, для чего нужен replot()?

Этот метод полностью перерисовывает график. Буржуи пишут, что его надо вызывать каждый раз для отображения изменения в отрисовке осей или точек графика.

Есть вопрос, я примерно по вашему примеру нарисовал графики, но у меня не получается сделать масштабирование по разным осям, то есть, есть график который рисуется по кнопке PushButton, и есть radiobutton в зависимости от того стоит галочка в radiobutton или нет масштабирование идет либо по оси x либо по оси y. Минус в том что без перезапуска программы по кнопке PushButton масштабирование не меняется (с оси х на ось у). Можно ли решить эту проблему? Чтобы без перезапуска программы можно было масштабировать либо по оси х либо по оси у?
Текст программы:

#include "plot.h"
#include "ui_plot.h"
#include "math.h"
#include <QMessageBox>

int vs=1;
Plot::Plot(QWidget *parent) :
QWidget(parent),
ui(new Ui::Plot)
{
ui->setupUi(this);
ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables);
}

Plot::~Plot()
{
delete ui;
}

void Plot::on_ScrollButton_pressed()
{
if(vs==0) vs=1;
else vs=0;
}

void Plot::on_pushButton_clicked()
{
int a,b;
a=ui->lineEdit->text().toInt();
b=ui->lineEdit_2->text().toInt();
if (a<(-360)||b>360)
{if (a<(-360))
{
QMessageBox::information(this,"Warnig!", "Change left border>-360!",QMessageBox::Ok | QMessageBox::Escape );
this->close();
} else
{QMessageBox::information(this,"Warnig!", "Change right border<360!",QMessageBox::Ok | QMessageBox::Escape );
this->close();
}
}
QVector<double> Ticks; // вектор с шагом в 30 градусов
int i = -360;
while(i<=360) {
Ticks << i;
i+=30;
}
int s=b-a+1;
ui->widget->xAxis->setTickVector(Ticks); // задаем созданный нами вектор
QVector<double> x(s), y(s); // строить будем до 360 градусов
if (ui->List->currentText()=="Sin")
{ for (int i=0; i<s; i++)
{
x[i] = i-abs(a);
y[i] = sin(x[i]*M_PI/180); // вычисляем синус
}
}
else if (ui->List->currentText()=="Cos")
{for (int i=0; i<s; i++)
{
x[i] = i-abs(a);
y[i] = cos(x[i]*M_PI/180);
}
}
else if (ui->List->currentText()=="Tg")
{for (int i=0; i<(s); ++i)
{
x[i] = i-abs(a);
y[i] = tan(x[i]*M_PI/180);
}
}
else if (ui->List->currentText()=="Ctg")
{for (int i=0; i<(s); ++i)
{
x[i] = i-abs(a);
y[i] = 1/(tan(x[i]*M_PI/180));
}
}

ui->widget->addGraph();// создаем график и добавляем данные:
ui->widget->graph(0)->setData(x, y);
ui->widget->xAxis->setLabel("x");// задаем имена осей координат
ui->widget->yAxis->setLabel("y");
ui->widget->xAxis->setRange(a, b);// задаем размеры осей
ui->widget->yAxis->setRange(-1, 1);
if(vs==0)
{
ui->widget->axisRect()->setRangeZoom(Qt::Vertical);
}
else
{
ui->widget->axisRect()->setRangeZoom(Qt::Horizontal);
}
ui->widget->replot();
}

Добрый день! У меня возникла необходимость в поле name для окон и графиков qCustomPlot использовать подстрочный и надстрочный текст ( индексы и степени). Не подскажете ли, как жто можно слелать?

Не могли бы вы конкретней описать куда вставлять // генерируем данные
QVector<double> x(360), y(360); // строить будем до 360 градусов
for (int i=0; i<360; ++i)
{
x[i] = i;
y[i] = 10*sin(x[i]*M_PI/180); // вычисляем синус
}
// создаем график и добавляем данные:
ui->widget->addGraph();
ui->widget->graph(0)->setData(x, y);
// задаем имена осей координат
ui->widget->xAxis->setLabel("x");
ui->widget->yAxis->setLabel("y");
// задаем размеры осей
ui->widget->xAxis->setRange(0, 360);
ui->widget->yAxis->setRange(-10, 10);
ui->widget->replot();
и что из этого в конечном варианте выйдет?

Добавить комментарий

Этот вопрос задается для того, чтобы выяснить, являетесь ли Вы человеком или представляете из себя автоматическую спам-рассылку.