使用Chart::Plot快速在数据中找到关系
上周我在工作中分析服务器日志数据,我的老板让我把它绘制成散点图。“没问题!”我想,打开Google Sheets。但是当我上传了250,000条记录来绘制时,Sheets的速度慢得像蜗牛。使用CPAN我发现了一个更好的东西: Chart::Plot。它有一个简单的界面,并且非常快。以下是使用它的方法。
散点图脚本
#!/usr/bin/env perl
use Chart::Plot;
open my $mlb, '<', '2017-so-hr.csv' or die $!;
my @series;
while (<$mlb>) {
chomp;
my ($x, $y) = split /\t/;
push @series, $x, $y;
}
my $img = Chart::Plot->new(800,640);
$img->setData(\@series, 'Points Noline Blue') or die $img->error;
$img->setGraphOptions (
vertGraphOffset => 100,
horGraphOffset => 75,
vertAxisLabel => 'HR',
horAxisLabel => 'SO',
title => '2017 MLB Strikeouts and Home Runs',
);
open my $fh, '>:raw', '2017-mlb-so-hr.png' or die $!;
print $fh $img->draw();
为了演示Chart::Plot,我从Lahman数据库中提取了2017年MLB投球数据,包括被击出的三振和本垒打,看看它们之间是否存在关系。
我的脚本打开csv(以制表符分隔)并解析它,将列推入@series
。它创建一个新的800x640像素的Chart::Plot对象,并调用setData
方法,将@series
的数组引用传递给它,并使用一个描述要绘制系列形状和颜色的样式字符串。以下是输出文件
初步观察这些数据似乎表明确实存在三振和本垒打之间的相关性,也许投球速度快投手投出的三振更多,但额外的速度却导致了更多的本垒打?
多个系列
要在图表上显示多个系列,只需为每个要添加的额外系列调用一次setData
。我已经更新了MLB数据,包括投手所在的联赛
#!/usr/bin/env perl
use Chart::Plot;
open my $mlb, '<', '2017-so-hr-lg.csv' or die $!;
my (@nl, @al);
while (<$mlb>) {
chomp;
my ($x, $y, $league) = split /\t/;
if ($league eq 'NL') {
push @nl, $x, $y;
}
else {
push @al, $x, $y;
}
}
my $img = Chart::Plot->new(800,640);
$img->setData(\@nl, 'Points Noline Blue') or die $img->error;
$img->setData(\@al, 'Points Noline Red') or die $img->error;
$img->setGraphOptions (
vertGraphOffset => 100,
horGraphOffset => 75,
vertAxisLabel => 'HR',
horAxisLabel => 'SO',
title => '2017 MLB Strikeouts and Home Runs',
);
open my $fh, '>:raw', '2017-mlb-so-hr-lg.png' or die $!;
print $fh $img->draw();
我将输入数据分成两个系列,一个为国家联赛,一个为美国联赛。然后我使用蓝色和红色样式为每个系列调用setData
。以下是结果
不透明图表
默认情况下,Chart::Plot生成的图表具有透明背景。如果您想添加白色背景,可以在命令行中使用convert
$ convert -flatten 2017-mlb-so-hr.png 2017-mlb-so-hr-whitebg.png
但是Chart::Plot让您可以直接访问底层GD图形对象,为什么不直接在脚本中操作它呢?
my $gd = $img->getGDobject();
my $white = $gd->colorAllocate(255,255,255);
$gd->filledRectangle(1,1,798,638,$white);
此代码片段通过调用colorAllocate
使用白色的RGB值创建一个新的白色颜色,这创建了颜色并返回其索引。然后它从左上角像素(加1以避免覆盖边界)开始绘制一个白色矩形,并延伸到右下角像素(减1)。
再次讨论三振和本垒打
如果我将每个投手在2017年的三振和本垒打次数除以他们投球的小时数,数据会讲述一个不同的故事
投手的三振和本垒打次数随着他们投球时间的增加而增加,但它们之间的关系几乎消失了……我的计量经济学生涯结束了。
总结
当您有大量数据时,Chart::Plot非常适合生成散点图或线图。其简单的界面和合理的默认值使得图表制作变得容易。
然而,由于它的样式字符串仅包含四种颜色,您只能在一个图表上绘制4个不同的数据系列。图表文本样式是硬编码到一个相当简朴的样式。虽然它确实提供了访问底层GD对象的方法,但逐像素绘制图像可能会非常繁琐。饼图和条形图不受支持,因此您需要使用其他模块来绘制这些图表。它不是一个通用图表库,而是一个专业工具。每个人的工具箱都应该有空间放置几个这样的工具。
标签
反馈
这篇文章有问题吗?请帮助我们通过在GitHub上打开问题或拉取请求来解决。