【问题标题】:How can I plot a time series graph with Perl?如何用 Perl 绘制时间序列图?
【发布时间】:2010-12-08 16:53:38
【问题描述】:

我有一些来自数据库 (SQLite) 的数据,将一个值(一个整数)映射到一个日期。日期是具有以下格式的字符串:YYYY-MM-DD hh:mm。日期分布不均匀。我想用X 上的日期和Y 上的值绘制一个折线图。使用 Perl 最简单的方法是什么?

我尝试了DBIx::Chart,但无法让它识别我的日期。我也试过GD::Graph,但正如文档所说:

GD::Graph 不支持数字 x 轴应有的方式。 X 的数据 轴应等距

【问题讨论】:

    标签: perl graph plot


    【解决方案1】:

    您可以使用 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 时间戳,但它是 DWIM。

    【讨论】:

    • DateTime::Format::DBI 工作得很好(委托给适当的 DateTime::Format::* 模块)
    • 我不知道 Chart::Clicker。但是显示人类友好日期的问题仍然存在。
    • Axis::DateTime 使用取决于范围的格式自动格式化日期。如果您不喜欢它的选择,您可以使用 DateTime 的 strftime 可接受的任何格式字符串调用它的 format 方法,它会使用它。您可以使用 Chart::Clicker::Axis 中的 tickstick_values 方法控制要显示的刻度线的数量和/或位置。
    • Chart::Clicker 看起来很棒,但不幸的是,我在 Win32 上使用 ActivePerl 5.10,Chart::Clicker 似乎无法作为 PPM 包使用。
    【解决方案2】:

    您可以使用Chart::Gnuplot 驱动gnuplot

    或者,如果 SVG 是可接受的输出格式,则有 SVG::TT::Graph

    【讨论】:

    • +1 到 Chart::Gnuplot。它是我最喜欢的图表模块,也是我发现的最简洁的 gnuplot 界面,它不涉及将原始命令传递给它。
    • 我确实设法用 gnuplot 绘制了我的数据,设置了正确的时间格式,看起来不错,但 X 轴从 1985 年延伸到 2010 年以上,而我的日期都在 2009 年。我仍然需要找到我如何对 gnuplot 说将 X 轴设置为仅从第一个日期延伸到最后一个日期。
    • @Sinan 我已经发现了,我希望自动范围。
    • 事实上我在滥用 Gnuplot。使用 Chart::Gnuplot::DataSet 选项 timefmt => '%Y-%m-%d %H:%M' 和 Chart::Gnuplot 选项 timeaxis => "x",它可以完美运行!
    【解决方案3】:

    我尝试了 DBIx::Chart,但无法让它识别我的日期。

    您是否尝试将日期转换为 Unix 时间戳并将其用作 X 日期?

    【讨论】:

    • 没有。转换我的日期的更好方法是什么?那么如何在 x 轴上查看日期而不是时间戳?
    • 我不认为 DBIx::Chart 支持这一点。因此,您可以对其进行子类化并添加此功能,或者采用 Sinan 对 Chart::Gnuplot 的建议,我赞成。
    • 与其因为您的代码中的一些问题(“我无法让它识别我的日期”)而放弃 DBIx::Chart,为什么不发布给您带来问题的代码,也许我们可以调试和你在一起吗?如果我们因为最初与他们的合作没有达到我们想要的效果而放弃解决方案,我们很快就会用完解决方案。
    【解决方案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 还支持多种输出格式。

      【讨论】:

      • 我想避免安装 gnuplot,但也许这样做更好。
      • 我不知道安装它是否更好,但任何图形解决方案都需要你安装一些东西,至少 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 做了类似的事情。这是一个令人难以置信的包,但它并不容易使用。

        【讨论】:

        • 我已经尝试使用 CSV 导出来使用 OpenOffice.org Calc 绘制它。我不需要实时,但我必须定期生成几张图表,每天至少一次,所以我想避免手动操作。
        【解决方案8】:

        以下内容在 SQLLite 中不起作用,因为不支持递归查询,但在 Oracle 中可以使用。

        您可以使用如下子查询为 Oracle dB 创建连续时间序列:

        (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 将失败。不能帮你,抱歉。

        【讨论】:

          猜你喜欢
          • 2018-08-31
          • 2022-01-10
          • 1970-01-01
          • 2020-02-22
          • 1970-01-01
          • 2018-10-22
          • 2020-03-29
          • 2023-03-22
          • 2023-03-25
          相关资源
          最近更新 更多