Используя Perl, как я могу создавать диаграммы, используя значения в CSV-файле? - PullRequest
2 голосов
/ 27 августа 2009

Я новичок в этом, и мне нужно понять, как выполнить эту задачу. У меня есть CSV-файл со следующими образцами данных:

site,type,2009-01-01,2009-01-02,....
X,A,12,10,...
X,B,10,23,...
Y,A,20,33,...
Y,B,3,12,...

and so on....

Я хочу создать Perl-скрипт для чтения данных из CSV-файла (согласно заданным данным пользователя) и создания диаграмм XY (разброса). Допустим, я хочу создать диаграмму для даты 2009-01-01 и типа B. Пользователь должен ввести что-то вроде «2009-01-01 B», и диаграмма должна быть создана со значениями из файла CSV.

Может кто-нибудь предложить мне какой-нибудь код для начала?

Ответы [ 4 ]

6 голосов
/ 27 августа 2009

Не начинайте с кода. Начните с CPAN.

CSV и Scatter

3 голосов
/ 27 августа 2009

Вот, пожалуйста, код для начала:

#!/usr/bin/perl -w
use strict;

use Text::CSV;
use GD;
use Getopt::Long;

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

2 голосов
/ 27 августа 2009

ОК, только для развлекательных целей :

#!/usr/bin/perl

use strict;
use warnings;

use DBI;
use List::AllUtils qw( each_array );

my $dbh = DBI->connect("DBI:CSV:f_dir=.", undef, undef, {
        RaiseError => 1, AutoCommit => 1,
    }
);

my $sth = $dbh->prepare(qq{
    SELECT d20090101 FROM test.csv WHERE type = ? and site = ?
});

$sth->execute('B', 'X');
my @x = map { $_->[0] } @{ $sth->fetchall_arrayref };

$sth->execute('B', 'Y');
my @y = map { $_->[0] } @{ $sth->fetchall_arrayref };

my @xy;

my $ea = each_array(@x, @y);
while ( my @vals = $ea->() ) {
    push @xy, \@vals;
}

my @canvas;
push @canvas, [ '|', (' ') x 40 ] for 1 .. 40;
push @canvas, [ '+', ('-') x 40 ];

for my $coord ( @xy ) {
    warn "coords=@$coord\n";
    my ($x, $y) = @$coord;
    $canvas[40 - $y]->[$x + 1] = '*';
}

print join "\n", map { join '', @$_ } @canvas;

Добавление осей и общее улучшение в ScatterPlot & mdash; действительно разочаровывающий модуль & ndash; оставлено в качестве упражнения для читателя.

Обратите внимание, что мне всегда приходится обманывать, когда дело доходит до SQL. Я был бы признателен за правильный JOIN, который устраняет необходимость в @x, @y и each_array.

Выход:

|
|
|
|            *
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|          *
|
|
+----------------------------------------
1 голос
/ 27 августа 2009

Мне нужно сделать несколько собственных графиков рассеяния, поэтому я поиграл с модулем, предложенным в других ответах. На мой вкус, точки данных, создаваемые GD :: Graph :: Cartesian , слишком велики, и модуль не предоставляет методов для управления этим параметром, поэтому я взломал свою копию Cartesian.pm iconsize, если вы хотите сделать то же самое).

use strict;
use warnings;
use Text::CSV;
use GD::Graph::Cartesian;

# Parse CSV file and convert the data for the
# requested $type and $date into a list of [X,Y] pairs.
my ($csv_file, $type, $date) = @ARGV;
my @xy_points;
my %i = ( X => -1, Y => -1 );
open(my $csv_fh, '<', $csv_file) or die $!;
my $parser = Text::CSV->new();
$parser->column_names( $parser->getline($csv_fh) );
while ( defined( my $hr = $parser->getline_hr($csv_fh) ) ){
    next unless $hr->{type} eq $type;
    my $xy = $hr->{site};
    $xy_points[++ $i{$xy}][$xy eq 'X' ? 0 : 1] = $hr->{$date};
}

# Make a graph.
my $graph = GD::Graph::Cartesian->new(
    width   => 400, # Image size (in pixels, not X-Y coordinates).
    height  => 400,
    borderx => 20,  # Margins (also pixels).
    bordery => 20,
    strings => [[ 20, 50, 'Graph title' ]],
    lines => [
        [ 0,0, 50,0 ], # Draw an X axis.
        [ 0,0,  0,50], # Draw a Y axis.
    ],
    points => \@xy_points, # The data.
);
open(my $png_file, '>', 'some_data.png') or die $!;
binmode $png_file;
print $png_file $graph->draw;
...