Как я могу построить график временных рядов с Perl?

У меня есть некоторые данные из базы данных (SQLite), сопоставляющие значение (целое число) с датой. Дата - это строка с таким форматом: YYYY-MM-DD hh:mm. Даты неравномерно распределены. Я хочу сделать линейный график с датами на X и значениями на Y. Каков самый простой способ сделать это с помощью Perl?

Я пробовал DBIx::Chart, но я не мог распознать свои даты. Я также попробовал GD::Graph, но, как говорится в документации:

GD:: Graph не поддерживает число x ось так, как должна. Данные для X оси должны быть равномерно распределены

Ответ 1

Вы можете управлять gnuplot с помощью Chart::Gnuplot.

В качестве альтернативы, если SVG является приемлемым форматом вывода, есть SVG::TT::Graph.

Ответ 2

Вы можете использовать Chart:: Clicker Axis:: DateTime:

#!/usr/local/bin/perl -w
use strict;
use Chart::Clicker;
use Chart::Clicker::Axis::DateTime;
use Chart::Clicker::Data::Series;
use Chart::Clicker::Data::DataSet;
use Chart::Clicker::Renderer::Point;

my $cc = Chart::Clicker->new;
my $series = Chart::Clicker::Data::Series->new(
    values    => [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ],
    keys      => [
        1256147117, 1256148117, 1256149117, 1256150117, 1256151117, 1256152117,
        1256153117, 1256154117, 1256155117, 1256156117
    ],
);
my $ctx = $cc->get_context('default');
$ctx->domain_axis(Chart::Clicker::Axis::DateTime->new(position => 'bottom', orientation     => 'horizontal'));
my $ds = Chart::Clicker::Data::DataSet->new(series => [ $series ]);
$cc->add_to_datasets($ds);
$cc->write_output('foo.png');

Вам нужно преобразовать свое время в метки времени Unix, но это DWIMs.

Ответ 3

Я попробовал DBIx:: Chart, но не смог распознать даты.

Вы пытались перевести свои даты на Unix-Timestamps и использовать их как даты X?

Ответ 4

Это сделало трюк для меня:

my $ctx = $chart->get_context('default');
$ctx->domain_axis(
    Chart::Clicker::Axis::DateTime->new(
        position        => 'bottom',
        orientation     => 'horizontal',
        ticks           => 5 ,
        format          => "%Y-%m-%d"
    )
);

Ответ 5

Самый простой способ, которым я нашел это с Perl, - использовать Perl для запуска процесса gnuplot. Вы можете использовать set timefmt x "%Y-%m-%d", и он будет автоматически анализировать данные в том формате, который у вас есть. Gnuplot также поддерживает различные форматы вывода.

Ответ 6

Я бы рекомендовал нормализовать даты для целых чисел. Разумный способ, конечно, будет использовать секунды эпохи, но это может показаться не слишком приятным на графике, поэтому нормализуйте линейным преобразованием в некоторый приличный диапазон (я могу предоставить подробную информацию о том, как вы хотите).

Ответ 7

Вам нужен ваш график для создания в реальном времени или для разового отчета? Если последнее, то вы можете использовать модули DateTime для генерации значений Excel и их графа в Excel (или его копии с открытым исходным кодом.)

use DateTime::Format::MySQL;
use DateTime::Format::Excel;

my $dt = DateTime::Format::MySQL->parse_datetime( '2003-01-16 23:12:01' );
print $dt, "\n";
my $daynum = DateTime::Format::Excel->format_datetime($dt);
print $daynum, "\n";

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

Ответ 8

В SQLLite не будет работать, поскольку рекурсивные запросы не поддерживаются, но он будет работать в Oracle.

Вы можете создать непрерывный временной ряд для Oracle dBs с подзапросом, подобным этому:

(SELECT   TRUNC (SYSDATE - x / 1440, 'MI') ts
             FROM   (SELECT       LEVEL x
                           FROM   DUAL
                     CONNECT BY   LEVEL <= 60))

Затем свяжите этот временной ряд с данными диаграммы с помощью LEFT JOIN следующим образом:

    SELECT   TO_CHAR (A.TS, 'DD/MM/YYYY HH24:MI') TS
        , b.DATAPOINT1, b.DATAPOINT2
   FROM   (SELECT   TRUNC (SYSDATE - x / 1440, 'MI') ts
             FROM   (SELECT       LEVEL x
                           FROM   DUAL
                     CONNECT BY   LEVEL <= 60)) a
        , MY_CHART_DATA b
  WHERE   a.ts = b.ts(+) ORDER BY   a.TS;

В приведенном выше примере будут отображаться последние 60 минут и будут работать ** с DBIx:: Chart. Чтобы изменить разрешение на часы, измените "MI" на "HH24" или на каждые 24 часа вы можете опустить параметр формата даты все вместе.

Чтобы изменить диапазон, просто установите значение CONNECT BY LEVEL для количества точек временного ряда, которые вам нужно построить, с заданным разрешением.

** Примечание: DBIx:: Chart будет barf, если все значения datapoint равны нулю (т.е. undefined). Не могу вам помочь, извините.