Передача данных из C ++ в пример gnuplot (с использованием интерфейса Gnuplot-iostream) - PullRequest
4 голосов
/ 16 января 2011

Я только что натолкнулся на интерфейс ввода / вывода g ++ от Dan Stahlke, который избавляет меня от «прокручивания моего собственного». К сожалению, примеров не так уж много, и реальной документации нет.

В моем проекте C ++ есть следующие типы данных:

struct Data
{
  std::string datestr;  // x axis value
  float f1;             // y axis series 1
  float f2;             // y axis series 2
  float f3;             // y axis series 3
};


typedef std::vector<Data> Dataset;

Я хочу передать переменную набора данных из C ++, чтобы я мог построить данные (даты на оси X и 3 числа, нанесенные в виде временных рядов на оси Y).

Может кто-нибудь показать мне, как перенести переменную Dataset из C ++ в gnuplot (используя интерфейс Gnuplot-iostream) и создать простой график, используя переданные данные?

Ответы [ 2 ]

6 голосов
/ 22 апреля 2013

Я недавно запустил новую версию в git, которая упрощает поддержку пользовательских типов данных, таких как эта.Для поддержки struct Data вы можете предоставить специализацию класса TextSender.Вот полный пример с использованием определенной вами структуры.

#include <vector>
#include "gnuplot-iostream.h"

struct Data {
    std::string datestr;  // x axis value
    float f1;             // y axis series 1
    float f2;             // y axis series 2
    float f3;             // y axis series 3
};

typedef std::vector<Data> Dataset;

namespace gnuplotio {
    template<>
    struct TextSender<Data> {
        static void send(std::ostream &stream, const Data &v) {
            TextSender<std::string>::send(stream, v.datestr);
            stream << " ";
            TextSender<float>::send(stream, v.f1);
            stream << " ";
            TextSender<float>::send(stream, v.f2);
            stream << " ";
            TextSender<float>::send(stream, v.f3);

            // This works too, but the longer version above gives
            // gnuplot-iostream a chance to format the numbers itself (such as
            // using a platform-independent 'nan' string).
            //stream << v.datestr << " " << v.f1 << " " << v.f2 << " " << v.f3;
        }
    };
}

int main() {
    Dataset x(2);
    // The http://www.gnuplot.info/demo/timedat.html example uses a tab between
    // date and time, but this doesn't seem to work (gnuplot interprets it as
    // two columns).  So I use a comma.
    x[0].datestr = "01/02/2003,12:34";
    x[0].f1 = 1;
    x[0].f2 = 2;
    x[0].f3 = 3;
    x[1].datestr = "02/04/2003,07:11";
    x[1].f1 = 10;
    x[1].f2 = 20;
    x[1].f3 = 30;

    Gnuplot gp;
    gp << "set timefmt \"%d/%m/%y,%H:%M\"\n";
    gp << "set xdata time\n";
    gp << "plot '-' using 1:2 with lines\n";
    gp.send1d(x);

    return 0;
}

Аналогичная вещь может быть проделана для поддержки отправки данных в двоичном формате.См. example-data-1d.cc в репозитории git для примера.

Кроме того, пользовательские типы данных, подобные этому, могут поддерживаться путем переопределения operator<<(std::ostream &, ...).

Другой вариант - использовать std::tuple (доступноC ++ 11) или boost::tuple вместо определения вашей собственной структуры.Они поддерживаются "из коробки" (ну, теперь они есть, но не в тот момент, когда вы задали вопрос).

1 голос
/ 22 декабря 2011

Вы смотрели примеры, которые идут с gnuplot-iostream?

Они немного разрежены, но показывают, как создать график из ряда точек данных:

Gnuplot gp;

gp << "set terminal png\n";

std::vector<double> y_pts;
for(int i=0; i<1000; i++) {
    double y = (i/500.0-1) * (i/500.0-1);
    y_pts.push_back(y);
}

gp << "set output 'my_graph_1.png'\n";
gp << "plot '-' with lines, sin(x/200) with lines\n";
gp.send(y_pts);
...