http://www.perlmonks.org?node_id=1011299

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I'd like to create a plot (just data points) where the x-values are dates like yyyy-mm-dd (no time needed, just day). The dates aren't consecutive, just various jumbled dates.

Looking at the docs for some of the various alternatives (GD::Graph, Chart::Gnuplot, Chart::Clicker, Chart), I don't see any mention of being able to automatically use dates (I want them to be treated like regular numerical values).

I suppose I could convert the dates to epoch times using DateTime, but then I'd have a plot showing epoch times in the x-axis instead of dates, but that would be difficult for readers to make sense of.

Should I used Datetime and fiddle with trying to convert date values and manually setting plot tick values, or can one of the plotting / charting modules do this for me?

Thanks!

  • Comment on Create a plot / chart with dates as x-values?

Replies are listed 'Best First'.
Re: Create a plot / chart with dates as x-values?
by BrowserUk (Patriarch) on Jan 02, 2013 at 16:26 UTC

    With GD, use the epoch numbers as the X-axis values, and set the option x_number_format to the address of a subroutine that will format the epoch number to a format suitable for display.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
    /li

      Hm... I've gotten this to sort-of work, but the x-data is not spaced properly (the dates are not all equidistant, but are shown as such on the plot). In fact, the docs say as much:

      "First of all: GD::Graph does not support numerical x axis the way it should. Data for X axes should be equally spaced. That understood: There is some support to make the printing of graphs with numerical X axis values a bit better, thanks to Scott Prahl."

      Here's the code:

      #!/usr/bin/env perl use Modern::Perl; use DateTime; use GD::Graph::points; my @x_vals = ( '2012-11-07', '2012-11-08', '2012-11-15', '2012-11-19', '2012-11-30', ); my @y_vals = ( 11, 12, 13, 14, 15, ); # ------------------------------------------- my @epoch_x_vals = (); for my $d (@x_vals) { my ($y, $m, $d) = split /-/, $d; push @epoch_x_vals, DateTime->new(year => $y, month => $m, day => $d) ->epoch; } my @data = (\@epoch_x_vals, \@y_vals); sub x_number_formatter { my ($e) = @_; my $dt = DateTime->from_epoch(epoch => $e); return $dt->ymd; } my $graph = GD::Graph::points->new(400, 300); $graph->set( x_label => 'X label', x_labels_vertical => 1, x_tick_number => 10, # experimented with this value a bit x_number_format => \&x_number_formatter, y_label => 'Y label', title => 'some title', ) or die $graph->error; my $gd = $graph->plot(\@data) or die $graph->error; open(my $img, '> plot.png') or die $!; binmode $img; print $img $gd->png;

      Will do some experimenting with gnuplot to see what I can get.

        Maybe this is closer to your liking:

        #! perl -slw use strict; use Time::Local qw[ timelocal ]; use POSIX qw[ strftime ]; use GD::Graph::points; my @x_vals = ( '2012-11-07', '2012-11-08', '2012-11-15', '2012-11-19', '2012-11-30', ); my @y_vals = ( 11, 12, 13, 14, 15, ); # ------------------------------------------- my @epoch_x_vals = map { my( $y, $m, $d ) = split /-/, $_; timelocal( 0,0,0, $d, $m, $y ); } @x_vals; my @data = (\@epoch_x_vals, \@y_vals); sub x_number_formatter { return strftime "%Y-%m-%d", localtime shift; +} my $graph = GD::Graph::points->new(400, 300); $graph->set( x_label => 'X label', x_labels_vertical => 1, x_tick_number => 5, # experimented with this value a bit x_min_value => $epoch_x_vals[ 0 ] - 1e6, x_max_value => $epoch_x_vals[ 4 ] + 1e6, x_number_format => \&x_number_formatter, y_label => 'Y label', title => 'some title', ) or die $graph->error; my $gd = $graph->plot(\@data) or die $graph->error; open(my $img, '> plot.png') or die $!; binmode $img; print $img $gd->png; close $img; system 'plot.png';

        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Create a plot / chart with dates as x-values?
by space_monk (Chaplain) on Jan 02, 2013 at 16:21 UTC
    I'm not sure what the exact problem is; Chart::Graph::Gnuplot has plenty of options for displaying dates on the x-axis and accepting point values in the same time format....

    In particular this section on reading and plotting date/time data seems to do the trick.

    ..perhaps you could clarify if I've missed something? :-)

    A Monk aims to give answers to those who have none, and to learn from those who know more.

      Missed this module. Will have a look. Thanks!

Re: Create a plot / chart with dates as x-values?
by Anonymous Monk on Jan 02, 2013 at 18:34 UTC

    Ok, thanks, all. Chart::Gnuplot did exactly what I wanted:

    #!/usr/bin/env perl use Modern::Perl; use DateTime; use Chart::Gnuplot; my @x_vals = qw/ 2012-11-07 2012-11-08 2012-11-15 2012-11-19 2012-11-30 /; my @y_vals = ( 11, 12, 13, 14, 15, ); my $chart = Chart::Gnuplot->new( output => 'plot.png', title => 'plot title', xlabel => 'x label', ylabel => 'y label', timeaxis => 'x', xtics => { labelfmt => '%Y-%m-%d', rotate => -90, }, ); my $dataset = Chart::Gnuplot::DataSet->new( xdata => \@x_vals, ydata => \@y_vals, title => 'data title', style => 'linespoints', timefmt => '%Y-%m-%d', ); $chart->plot2d($dataset);

    As noted in its docs, useful examples at http://chartgnuplot.sourceforge.net/.