如何在GD :: Graph :: linespoints折线图中添加垂直线?

时间:2019-05-24 21:56:21

标签: perl graph

我的折线图很好,但是我想添加垂直线以表示“时间轴”日期。

use GD::Graph::linespoints;
use GD::Graph::Data;

my @label = qw(2019-05-05 2019-05-12 2019-05-19 2019-05-26);
my @data = (10, 20, 30, 40);
my @events = qw(2019-05-07 2019-05-15 2019-05-30);

my @input = (\@label, \@data);
my $data = GD::Graph::Data->new(\@input) or die GD::Graph::Data->error;
my $graph = GD::Graph::linespoints->new(1400,600);
$graph->set(
  x_label               => 'Week',
  x_label_position      => .5,
  y_label               => 'Things',
  y_min_value           => 0,
  title                 => 'Average Daily Things',
  x_labels_vertical     => 1,
  textclr               => 'orange',
  labelclr              => 'orange',
  axislabelclr          => 'gray',
  fgclr                 => 'green',
  bgclr                 => 'white',
  shadow_depth          => 3,
  markers               => 1,
  marker_size           => 2,
  shadowclr             => 'dgreen',
  transparent           => 0,
  dclrs                 => [ qw(blue) ],
) or die $graph->error;
$graph->plot($data) or die $graph->error;
my $file = 'testing.png';
open OUT, '>', $file or die "Cannot open '$file' for write: $!";
binmode OUT;
print OUT $graph->gd->png;
close OUT;

所需的输出:

  • 垂直线应根据实际日期在点之间隔开,但也可以将其对齐到先前的刻度线。
  • 垂直线应从上边框到下边框完全横穿。
  • 文字说明,如果可能的话,说明突出显示的日期。

2 个答案:

答案 0 :(得分:1)

似乎无法在特定位置直接向GD::Graph添加垂直线,但是您可以在使用$graph->plot()完成GD::Polyline之后添加线。例如:

use strict;
use warnings;
use GD::Graph::mixed;
use GD::Polyline;

my $start_day = 5;
my $end_day = 26;
my @data = (10, 20, 30, 40);
my @label = qw(2019-05-05 2019-05-12 2019-05-19 2019-05-26);
my @all_labels = map { sprintf "2019-05-%02d", $_ } $start_day..$end_day;
my $N = scalar @all_labels;
my $label_indices = get_event_indices( \@all_labels, \@label );
my $ydata = linear_interpolation(\@data, $label_indices, $N);
my @events = qw(2019-05-07 2019-05-15 2019-05-26);

my $points_data1 = get_point_data( \@all_labels, \@label, $ydata);

my @plot_data = (\@all_labels, $ydata, $points_data1);

my $width = 1400;
my $height = 600;
my $graph = GD::Graph::mixed->new($width, $height);
$graph->set(
  axislabelclr          => 'gray',
  bgclr                 => 'white',
  dclrs                 => [ qw(blue) ],
  fgclr                 => 'green',
  labelclr              => 'orange',
  marker_size           => 2,
  markers               => 1,
  shadowclr             => 'dgreen',
  shadow_depth          => 3,
  textclr               => 'orange',
  title                 => 'Average Daily Things',
  transparent           => 0,
  types                 => [ qw( lines points  ) ],
  x_label               => 'Week',
  x_label_position      => .5,
  x_label_skip          => 7,
  x_labels_vertical     => 1,
  y_label               => 'Things',
  y_min_value           => 0,
) or die $graph->error;
$graph->plot(\@plot_data) or die $graph->error;

my $event_indices = get_event_indices( \@all_labels, \@events );

plot_vertical_lines( $graph, $height, $event_indices );

my $file = 'testing.png';
open OUT, '>', $file or die "Cannot open '$file' for write: $!";
binmode OUT;
print OUT $graph->gd->png;
close OUT;

sub plot_vertical_lines {
    my ( $graph, $height, $event_indices ) = @_;

    my $gd = $graph->gd;
    my $black  = $gd->colorAllocate(  0,  0,  0);

    for my $idx ( @$event_indices ) {
        my @line = $graph->get_hotspot(1, $idx);
        my $x = $line[3];
        my $polyline = GD::Polyline->new();

        # add some points
        $polyline->addPt(  $x, 20);
        $polyline->addPt(  $x, $height - 70);
        $gd->setThickness( 2);
        $gd->polydraw($polyline, $black);
    }
}

sub get_event_indices {
    my ( $l1, $l2 ) = @_;

    my @idx;
    my $j = 0;
    for my $i (0..$#$l1) {
        my $label = $l1->[$i];
        if ( $label eq $l2->[$j] ) {
            push @idx, $i;
            $j++;
        }
    }
    return \@idx;
}

sub get_point_data {
    my ( $l1, $l2, $ydata) = @_;

    my @data;
    my $j = 0;
    for my $i (0..$#$l1) {
        my $label = $l1->[$i];
        if ( $label eq $l2->[$j] ) {
            push @data, $ydata->[$i];
            $j++;
        }
        else {
            push @data, undef;
        }
    }
    return \@data;
}

sub linear_interpolation {
    my ($data, $indices, $N) = @_;

    my @all_data = (undef) x $N;
    my $k = 0;
    for my $i (0..($#$data - 1)) {
        my $min = $data->[$i];
        my $max = $data->[$i + 1];
        my $N2 = $indices->[$i + 1] - $indices->[$i];
        my $step = ($max - $min) / $N2;
        for my $j (0..$N2) {
            $all_data[$k] = $min + $step * $j;
            $k++ if $j < $N2;
        }
    }
    return \@all_data;
}

enter image description here

答案 1 :(得分:0)