Synopsis
Take a data structure in Perl, and automatically write a Python3 script using matplotlib to generate an image. The Python3 script is saved in /tmp, to be edited at the user's discretion. Requires python3 and matplotlib installations.
Single Plots
Simplest use case:
use Matplotlib::Simple 'plot';
plot({
'output.filename' => '/tmp/gospel.word.counts.png',
'plot.type' => 'bar',
data => {
Matthew => 18345,
Mark => 11304,
Luke => 19482,
John => 15635,
}
});
where xlabel, ylabel, title, etc. are axis methods in matplotlib itself. plot.type, data, input.file are all specific to MatPlotLib::Simple.
Multiple Plots
Having a plots argument as an array lets the module know to create subplots:
use Matplotlib::Simple 'plot';
plot({
'output.filename' => 'svg/pies.png',
plots => [
{
data => {
Russian => 106_000_000, # Primarily European Russia
German => 95_000_000, # Germany, Austria, Switzerland, etc.
},
'plot.type' => 'pie',
title => 'Top Languages in Europe',
suptitle => 'Pie in subplots',
},
{
data => {
Russian => 106_000_000, # Primarily European Russia
German => 95_000_000, # Germany, Austria, Switzerland, etc.
},
'plot.type' => 'pie',
title => 'Top Languages in Europe',
},
],
ncols => 2,
});
which produces the following subplots image:
bar, barh, boxplot, hexbin, hist, hist2d, imshow, pie, plot, scatter, and violinplot all match the methods in matplotlib itself. =head1 Examples/Plot Types
Consider the following helper subroutines to generate data to plot:
sub linspace { # mostly written by Grok
my ($start, $stop, $num, $endpoint) = @_; # endpoint means include $stop
$num = defined $num ? int($num) : 50; # Default to 50 points
$endpoint = defined $endpoint ? $endpoint : 1; # Default to include endpoint
return () if $num < 0; # Return empty array for invalid num
return ($start) if $num == 1; # Return single value if num is 1
my (@result, $step);
if ($endpoint) {
$step = ($stop - $start) / ($num - 1) if $num > 1;
for my $i (0 .. $num - 1) {
$result[$i] = $start + $i * $step;
}
} else {
$step = ($stop - $start) / $num;
for my $i (0 .. $num - 1) {
$result[$i] = $start + $i * $step;
}
}
return @result;
}
sub generate_normal_dist {
my ($mean, $std_dev, $size) = @_;
$size = defined $size ? int $size : 100; # default to 100 points
my @numbers;
for (1 .. int($size / 2) + 1) {# Box-Muller transform
my $u1 = rand();
my $u2 = rand();
my $z0 = sqrt(-2.0 * log($u1)) * cos(2.0 * 3.141592653589793 * $u2);
my $z1 = sqrt(-2.0 * log($u1)) * sin(2.0 * 3.141592653589793 * $u2); # Scale and shift to match mean and std_dev
push @numbers, ($z0 * $std_dev + $mean, $z1 * $std_dev + $mean);
} # Trim to exact size if needed
@numbers = @numbers[0 .. $size - 1] if @numbers > $size;
@numbers = map {sprintf '%.1f', $_} @numbers;
return \@numbers;
}
sub rand_between {
my ($min, $max) = @_;
return $min + rand($max - $min)
}
Barplot/bar/barh
Plot a hash or a hash of arrays as a boxplot
Options
| Option | Description | Example |
| -------- | ------- | ------- |
| color | :mpltype:`color` or list of :mpltype:`color`, optional; The colors of the bar faces. This is an alias for *facecolor*. If both are given, *facecolor* takes precedence # if entering multiple colors, quoting isn't needed | `color => ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'fuchsia'],` or a single color for all bars `color => 'red'` |
| edgecolor | :mpltype:`color` or list of :mpltype:`color`, optional; The colors of the bar edges | `edgecolor => 'black'` |
| key.order | define the keys in an order (an array reference) | `'key.order' => ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'],` |
| linewidth | float or array, optional; Width of the bar edge(s). If 0, don't draw edges. Only does anything with defined `edgecolor` | `linewidth => 2,` |
| log | bool, default: False; If *True*, set the y-axis to be log scale. | `log = 'True',` |
| stacked | stack the groups on top of one another; default 0 = off | `stacked => 1,` |
| width | float only, default: 0.8; The width(s) of the bars. `width` will be deactivated with grouped, non-stacked bar plots | `width => 0.4,` |
| xerr | float or array-like of shape(N,) or shape(2, N), optional. If not *None*, add horizontal / vertical errorbars to the bar tips. The values are +/- sizes relative to the data: - scalar: symmetric +/- values for all bars # - shape(N,): symmetric +/- values for each bar # - shape(2, N): Separate - and + values for each bar. First row # contains the lower errors, the second row contains the upper # errors. # - *None*: No errorbar. (Default) | `yerr => {'USA' => [15,29], 'Russia' => [199,1000],}` |
| yerr | same as xerr, but better with bar |
an example of multiple plots, showing many options:
single, simple plot
use Matplotlib::Simple 'plot';
plot({
'output.filename' => 'output.images/single.barplot.png',
data => { # simple hash
Fri => 76, Mon => 73, Sat => 26, Sun => 11, Thu => 94, Tue => 93, Wed => 77
},
'plot.type' => 'bar',
xlabel => '# of Days',
ylabel => 'Count',
title => 'Customer Calls by Days'
});
where xlabel, ylabel, title, etc. are axis methods in matplotlib itself. plot.type, data, input.file are all specific to MatPlotLib::Simple.
multiple plots
plot({
'input.file' => $tmp_filename,
execute => 0,
'output.filename' => 'output.images/barplots.png',
plots => [
{ # simple plot
data => { # simple hash
Fri => 76, Mon => 73, Sat => 26, Sun => 11, Thu => 94, Tue => 93, Wed => 77
},
'plot.type' => 'bar',
'key.order' => ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'],
suptitle => 'Types of Plots', # applies to all
color => ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'fuchsia'],
edgecolor => 'black',
set_figwidth => 40/1.5, # applies to all plots
set_figheight => 30/2, # applies to all plots
title => 'bar: Rejections During Job Search',
xlabel => 'Day of the Week',
ylabel => 'No. of Rejections'
},
{ # grouped bar plot
'plot.type' => 'bar',
data => {
1941 => {
UK => 6.6,
US => 6.2,
USSR => 17.8,
Germany => 26.6
},
1942 => {
UK => 7.6,
US => 26.4,
USSR => 19.2,
Germany => 29.7
},
1943 => {
UK => 7.9,
US => 61.4,
USSR => 22.5,
Germany => 34.9
},
1944 => {
UK => 7.4,
US => 80.5,
USSR => 27.0,
Germany => 31.4
},
1945 => {
UK => 5.4,
US => 83.1,
USSR => 25.5,
Germany => 11.2 #Rapid decrease due to war's end <br />
},
},
stacked => 0,
title => 'Hash of Hash Grouped Unstacked Barplot',
width => 0.23,
xlabel => 'r"$\it{anno}$ $\it{domini}$"', # italic
ylabel => 'Military Expenditure (Billions of $)'
},
{ # grouped bar plot
'plot.type' => 'bar',
data => {
1941 => {
UK => 6.6,
US => 6.2,
USSR => 17.8,
Germany => 26.6
},
1942 => {
UK => 7.6,
US => 26.4,
USSR => 19.2,
Germany => 29.7
},
1943 => {
UK => 7.9,
US => 61.4,
USSR => 22.5,
Germany => 34.9
},
1944 => {
UK => 7.4,
US => 80.5,
USSR => 27.0,
Germany => 31.4
},
1945 => {
UK => 5.4,
US => 83.1,
USSR => 25.5,
Germany => 11.2 #Rapid decrease due to war's end
},
},
stacked => 1,
title => 'Hash of Hash Grouped Stacked Barplot',
xlabel => 'r"$\it{anno}$ $\it{domini}$"', # italic
ylabel => 'Military Expenditure (Billions of $)'
},
{# grouped barplot: arrays indicate Union, Confederate which must be specified in options hash
data => { # 4th plot: arrays indicate Union, Confederate which must be specified in options hash
'Antietam' => [ 12400, 10300 ],
'Gettysburg' => [ 23000, 28000 ],
'Chickamauga' => [ 16000, 18000 ],
'Chancellorsville' => [ 17000, 13000 ],
'Wilderness' => [ 17500, 11000 ],
'Spotsylvania' => [ 18000, 12000 ],
'Cold Harbor' => [ 12000, 5000 ],
'Shiloh' => [ 13000, 10700 ],
'Second Bull Run' => [ 10000, 8000 ],
'Fredericksburg' => [ 12600, 5300 ],
},
'plot.type' => 'barh',
color => ['blue', 'gray'], # colors match indices of data arrays
label => ['North', 'South'], # colors match indices of data arrays
xlabel => 'Casualties',
ylabel => 'Battle',
title => 'barh: hash of array'
},
{ # 5th plot: barplot with groups
data => {
1942 => [ 109867, 310000, 7700000 ], # US, Japan, USSR
1943 => [ 221111, 440000, 9000000 ],
1944 => [ 318584, 610000, 7000000 ],
1945 => [ 318929, 1060000, 3000000 ],
},
color => ['blue', 'pink', 'red'], # colors match indices of data arrays
label => ['USA', 'Japan', 'USSR'], # colors match indices of data arrays
'log' => 1,
title => 'grouped bar: Casualties in WWII',
ylabel => 'Casualties',
'plot.type' => 'bar'
}, <br />
{ # nuclear weapons barplot
'plot.type' => 'bar',
data => {
'USA' => 5277, # FAS Estimate
'Russia' => 5449, # FAS Estimate
'UK' => 225, # Consistent estimate
'France' => 290, # Consistent estimate
'China' => 600, # FAS Estimate
'India' => 180, # FAS Estimate
'Pakistan' => 130, # FAS Estimate
'Israel' => 90, # FAS Estimate
'North Korea' => 50, # FAS Estimate
},
title => 'Simple hash for barchart with yerr',
xlabel => 'Country',
yerr => {
'USA' => [15,29],
'Russia' => [199,1000],
'UK' => [15,19],
'France' => [19,29],
'China' => [200,159],
'India' => [15,25],
'Pakistan' => [15,49],
'Israel' => [90,50],
'North Korea' => [10,20],
},
ylabel => '# of Nuclear Warheads',
'log' => 'True', # linewidth => 1,
}
],
ncols => 3,
nrows => 4
});
which produces the plot:
boxplot
Plot a hash of arrays as a series of boxplots
options
| Option | Description | Example |
| -------- | ------- | ------- |
| `color` | a single color for all plots | `color => 'pink'` |
| `colors` | a hash, where each data point and color is a hash pair | `colors => { A => 'orange', E => 'yellow', B => 'purple' },` |
| `key.order` | order that the keys in the entry hash will be plotted | `key.order = ['A', 'E', 'B']` |
| `orientation` | orientation of the plot, by default `vertical` | `orientation = 'horizontal'` |
| `showcaps` | Show the caps on the ends of whiskers; default `True` | `showcaps => 'False',` |
| `showfliers` | Show the outliers beyond the caps; default `True` | `showfliers => 'False'` |
| `showmeans` | show means; default = `True` | `showmeans => 'False'` |
| `whiskers` | show whiskers, default = 1 | ` whiskers => 0,` |
single, simple plot
my $x = generate_normal_dist( 100, 15, 3 * 10 );
my $y = generate_normal_dist( 85, 15, 3 * 10 );
my $z = generate_normal_dist( 106, 15, 3 * 10 );
single plots are simple
plot({
'output.filename' => 'output.images/single.boxplot.png',
data => { # simple hash
E => [ 55, @{$x}, 160 ],
B => [ @{$y}, 140 ],
# A => @a
},
'plot.type' => 'boxplot',
title => 'Single Box Plot: Specified Colors',
colors => { E => 'yellow', B => 'purple' },
'input.file' => $tmp_filename,
execute => 0,
});
which makes the following image:
multiple plots
plot({
'output.filename' => 'output.images/boxplot.png',
execute => 0,
'input.file' => $tmp_filename,
plots => [
{
data => {
A => [ 55, @{$z} ],
E => [ @{$y} ],
B => [ 122, @{$z} ],
},
title => 'Simple Boxplot',
ylabel => 'ylabel',
xlabel => 'label',
'plot.type' => 'boxplot',
suptitle => 'Boxplot examples'
},
{
color => 'pink',
data => {
A => [ 55, @{$z} ],
E => [ @{$y} ],
B => [ 122, @{$z} ],
},
title => 'Specify single color',
ylabel => 'ylabel',
xlabel => 'label',
'plot.type' => 'boxplot'
},
{
colors => {
A => 'orange',
E => 'yellow',
B => 'purple'
},
data => {
A => [ 55, @{$z} ],
E => [ @{$y} ],
B => [ 122, @{$z} ],
},
title => 'Specify set-specific color; showfliers = False',
ylabel => 'ylabel',
xlabel => 'label',
'plot.type' => 'boxplot',
showmeans => 'True',
showfliers => 'False',
set_figwidth => 12
},
{
colors => {
A => 'orange',
E => 'yellow',
B => 'purple'
},
data => {
A => [ 55, @{$z} ],
E => [ @{$y} ],
B => [ 122, @{$z} ],
},
title => 'Specify set-specific color; showmeans = False',
ylabel => 'ylabel',
xlabel => 'label',
'plot.type' => 'boxplot',
showmeans => 'False',
},
{
colors => {
A => 'orange',
E => 'yellow',
B => 'purple'
},
data => {
A => [ 55, @{$z} ],
E => [ @{$y} ],
B => [ 122, @{$z} ],
},
title => 'Set-specific color; orientation = horizontal',
ylabel => 'ylabel',
xlabel => 'label',
orientation => 'horizontal',
'plot.type' => 'boxplot',
},
{
colors => {
A => 'orange',
E => 'yellow',
B => 'purple'
},
data => {
A => [ 55, @{$z} ],
E => [ @{$y} ],
B => [ 122, @{$z} ],
},
title => 'Notch = True',
ylabel => 'ylabel',
xlabel => 'label',
notch => 'True',
'plot.type' => 'boxplot',
},
{
colors => {
A => 'orange',
E => 'yellow',
B => 'purple'
},
data => {
A => [ 55, @{$z} ],
E => [ @{$y} ],
B => [ 122, @{$z} ],
},
title => 'showcaps = False',
ylabel => 'ylabel',
xlabel => 'label',
showcaps => 'False',
'plot.type' => 'boxplot',
set_figheight => 12,
},
],
ncols => 3,
nrows => 3,
});
which makes the following plot:
hexbin
Plot a hash of arrays as a hexbin see https://matplotlib.org/stable/api/asgen/matplotlib.pyplot.hexbin.html
options
| Option | Description | Example |
| -------- | ------- | ------- |
| cb_logscale | colorbar log scale `from matplotlib.colors import LogNorm` | default 0, any value > 0 enables |
| cmap | The Colormap instance or registered colormap name used to map scalar data to colors | default `gist_rainbow` |
| key.order | define the keys in an order (an array reference) | `'key.order' => ['X-rays', 'Yak Butter'],` |
| marginals | integer, by default off = 0 | `marginals => 1` |
| mincnt | int >= 0, default: None; If not None, only display cells with at least mincnt number of points in the cell. | `mincnt => 2` |
| vmax | The normalization method used to scale scalar data to the [0, 1] range before mapping to colors using cmap | `'asinh', 'function', 'functionlog', 'linear', 'log', 'logit', 'symlog'` default `linear` |
| vmin | The normalization method used to scale scalar data to the [0, 1] range before mapping to colors using cmap | `'asinh', 'function', 'functionlog', 'linear', 'log', 'logit', 'symlog'` default `linear` |
| xbins | integer that accesses horizontal gridsize | default is 15 |
| xscale.hexbin | 'linear', 'log'}, default: 'linear': Use a linear or log10 scale on the horizontal axis | `'xscale.hexbin' => 'log'` |
| ybins | integer that accesses vertical gridsize | default is 15 |
| yscale.hexbin | 'linear', 'log'}, default: 'linear': Use a linear or log10 scale on the vertical axis | `'yscale.hexbin' => 'log'` |
single, simple plot
plot({
data => {
E => generate_normal_dist(100, 15, 3*210),
B => generate_normal_dist(85, 15, 3*210)
},
'output.filename' => 'output.images/single.hexbin.png',
'plot.type' => 'hexbin',
set_figwidth => 12,
title => 'Simple Hexbin',
});
which makes the following plot:
multiple plots
plot({
'input.file' => $tmp_filename,
execute => 0,
'output.file' => 'output.images/hexbin.png',
plots => [
{
data => {
E => @e,
B => @b
},
'plot.type' => 'hexbin',
title => 'Simple Hexbin',
},
{
data => {
E => @e,
B => @b
},
'plot.type' => 'hexbin',
title => 'colorbar logscale',
cb_logscale => 1
},
{
cmap => 'jet',
data => {
E => @e,
B => @b
},
'plot.type' => 'hexbin',
title => 'cmap is jet',
xlabel => 'xlabel',
},
{
data => {
E => @e,
B => @b
},
'key.order' => ['E', 'B'],
'plot.type' => 'hexbin',
title => 'Switch axes with key.order',
},
{
data => {
E => @e,
B => @b
},
'plot.type' => 'hexbin',
title => 'vmax set to 25',
vmax => 25
},
{
data => {
E => @e,
B => @b
},
'plot.type' => 'hexbin',
title => 'vmin set to -4',
vmin => -4
},
{
data => {
E => @e,
B => @b
},
'plot.type' => 'hexbin',
title => 'mincnt set to 7',
mincnt => 7
},
{
data => {
E => @e,
B => @b
},
'plot.type' => 'hexbin',
title => 'xbins set to 9',
xbins => 9
},
{
data => {
E => @e,
B => @b
},
'plot.type' => 'hexbin',
title => 'ybins set to 9',
ybins => 9
},
{
data => {
E => @e,
B => @b
},
'plot.type' => 'hexbin',
title => 'marginals = 1',
marginals => 1
},
{
data => {
E => @e,
B => @b
},
'plot.type' => 'hexbin',
title => 'xscale.hexbin = 1',
'xscale.hexbin' => 'log'
},
{
data => {
E => @e,
B => @b
},
'plot.type' => 'hexbin',
title => 'yscale.hexbin = 1',
'yscale.hexbin' => 'log'
},
],
ncols => 4,
nrows => 3,
scale => 5,
suptitle => 'Various Changes to Standard Hexbin: All data is the same'
});
which produces the following image:
hist
Plot a hash of arrays as a series of histograms
options
| Option | Description | Example |
| -------- | ------- | ------- |
| `alpha` | default 0.5; same for all sets | |
| `bins` | # nt or sequence or str, default: :rc:`hist.bins`If *bins* is an integer, it defines the number of equal-width bins in the range. If *bins* is a sequence, it defines the bin edges, including the left edge of the first bin and the right edge of the last bin; in this case, bins may be unequally spaced. All but the last (righthand-most) bin is half-open | |
| `color` | a hash, where keys are the keys in data, and values are colors | `X => 'blue'` |
| `log` | if set to > 1, the y-axis will be logarithmic | |
| `orientation` | {'vertical', 'horizontal'}, default: 'vertical' |
single, simple plot
my @e = generate_normal_dist( 100, 15, 3 * 200 );
my @b = generate_normal_dist( 85, 15, 3 * 200 );
my @a = generate_normal_dist( 105, 15, 3 * 200 );
plot({
'input.file' => $tmp_filename,
execute => 0,
'output.filename' => 'output.images/single.hist.png',
data => {
E => @e,
B => @b,
A => @a,
},
'plot.type' => 'hist'
});
which makes the following simple plot:
multiple plots
plot({
'input.file' => $tmp_filename,
execute => 0,
'output.file' => 'output.images/histogram.png',
set_figwidth => 15,
suptitle => 'hist Examples',
plots => [
{ # 1st subplot
data => {
E => @e,
B => @b,
A => @a,
},
'plot.type' => 'hist',
alpha => 0.25,
bins => 50,
title => 'alpha = 0.25',
color => {
B => 'Black',
E => 'Orange',
A => 'Yellow',
},
scatter => '['
. join( ',', 22 .. 44 ) . '],[' # x coords
. join( ',', 22 .. 44 ) # y coords
. '], label = "scatter"',
xlabel => 'Value',
ylabel => 'Frequency',
},
{ # 2nd subplot
data => {
E => @e,
B => @b,
A => @a,
},
'plot.type' => 'hist',
alpha => 0.75,
bins => 50,
title => 'alpha = 0.75',
color => {
B => 'Black',
E => 'Orange',
A => 'Yellow',
},
xlabel => 'Value',
ylabel => 'Frequency',
},
{ # 3rd subplot
add => [ # add secondary plots/graphs/methods
{ # 1st additional plot/graph
data => {
'Gaussian' => [
[40..150],
[map {150 * exp(-0.5*($_-100)**2)} 40..150]
]
},
'plot.type' => 'plot',
'set.options' => {
'Gaussian' => 'color = "red", linestyle = "dashed"'
}
}
],
data => {
E => @e,
B => @b,
A => @a,
},
'plot.type' => 'hist',
alpha => 0.75,
bins => {
A => 10,
B => 25,
E => 50
},
title => 'Varying # of bins',
color => {
B => 'Black',
E => 'Orange',
A => 'Yellow',
},
xlabel => 'Value',
ylabel => 'Frequency',
},
{# 4th subplot
data => {
E => @e,
B => @b,
A => @a,
},
'plot.type' => 'hist',
alpha => 0.75,
color => {
B => 'Black',
E => 'Orange',
A => 'Yellow',
},
orientation => 'horizontal', # assign x and y labels smartly
title => 'Horizontal orientation',
ylabel => 'Value',
xlabel => 'Frequency', # 'log' => 1,
},
],
ncols => 3,
nrows => 2,
});
hist2d
options
single, simple plot
multiple plots
imshow
Plot 2D array of numbers as an image
options
| Option | Description | Example |
| -------- | ------- | ------- |
| `cblabel` | colorbar label | `cblabel => 'sin(x) * cos(x)',` |
| `cbdrawedges` | draw edges for colorbar | |
| `cblocation` | 'left', 'right', 'top', 'bottom' | `cblocation => 'left',` |
| `cborientation` | None, or 'vertical', 'horizontal' | |
| `cmap` | # The Colormap instance or registered colormap name used to map scalar data to colors. | |
| `vmax` | float | |
| `vmin` | float |
single, simple plot
my @imshow_data;
foreach my $i (0..360) {
foreach my $j (0..360) {
push @{ $imshow_data[$i] }, sin($i * $pi/180)*cos($j * $pi/180);
}
}
plot({
data => \@imshow_data,
execute => 0,
'input.file' => $tmp_filename,
'output.filename' => 'output.images/imshow.single.png',
'plot.type' => 'imshow',
set_xlim => '0, ' . scalar @imshow_data,
set_ylim => '0, ' . scalar @imshow_data,
});
which makes the following image:
multiple plots
plot({
plots => [
{
data => \@imshow_data,
'plot.type' => 'imshow',
set_xlim => '0, ' . scalar @imshow_data,
set_ylim => '0, ' . scalar @imshow_data,
title => 'basic',
},
{
cblabel => 'sin(x) * cos(x)',
data => \@imshow_data,
'plot.type' => 'imshow',
set_xlim => '0, ' . scalar @imshow_data,
set_ylim => '0, ' . scalar @imshow_data,
title => 'cblabel',
},
{
cblabel => 'sin(x) * cos(x)',
cblocation => 'left',
data => \@imshow_data,
'plot.type' => 'imshow',
set_xlim => '0, ' . scalar @imshow_data,
set_ylim => '0, ' . scalar @imshow_data,
title => 'cblocation = left',
},
{
cblabel => 'sin(x) * cos(x)',
data => \@imshow_data,
add => [ # add secondary plots
{ # 1st additional plot
data => {
'sin(x)' => [
[0..360],
[map {180 + 180*sin($_ * $pi/180)} 0..360]
],
'cos(x)' => [
[0..360],
[map {180 + 180*cos($_ * $pi/180)} 0..360]
],
},
'plot.type' => 'plot',
'set.options' => {
'sin(x)' => 'color = "red", linestyle = "dashed"',
'cos(x)' => 'color = "blue", linestyle = "dashed"',
}
}
],
'plot.type' => 'imshow',
set_xlim => '0, ' . scalar @imshow_data,
set_ylim => '0, ' . scalar @imshow_data,
title => 'auxiliary plots',
},
],
execute => 0,
'input.file' => $tmp_filename,
'output.file' => 'output.images/imshow.multiple.png',
ncols => 2,
nrows => 2,
set_figheight => 6*3,# 4.8
set_figwidth => 6*4 # 6.4
});
which makes the following image:
pie
options
single, simple plot
plot({
'output.file' => 'output.images/single.pie.png',
data => { # simple hash
Fri => 76,
Mon => 73,
Sat => 26,
Sun => 11,
Thu => 94,
Tue => 93,
Wed => 77
},
'plot.type' => 'pie',
title => 'Single Simple Pie',
'input.file' => $tmp_filename,
execute => 0,
});
which makes the image:
multiple plots
plot({
'output.file' => 'output.images/pie.png',
plots => [
{
data => {
'Russian' => 106_000_000, # Primarily European Russia
'German' =>
95_000_000, # Germany, Austria, Switzerland, etc.
'English' => 70_000_000, # UK, Ireland, etc.
'French' => 66_000_000, # France, Belgium, Switzerland, etc.
'Italian' => 59_000_000, # Italy, Switzerland, etc.
'Spanish' => 45_000_000, # Spain
'Polish' => 38_000_000, # Poland
'Ukrainian' => 32_000_000, # Ukraine
'Romanian' => 24_000_000, # Romania, Moldova
'Dutch' => 22_000_000 # Netherlands, Belgium
},
'plot.type' => 'pie',
title => 'Top Languages in Europe',
suptitle => 'Pie in subplots',
},
{
data => {
'Russian' => 106_000_000, # Primarily European Russia
'German' =>
95_000_000, # Germany, Austria, Switzerland, etc.
'English' => 70_000_000, # UK, Ireland, etc.
'French' => 66_000_000, # France, Belgium, Switzerland, etc.
'Italian' => 59_000_000, # Italy, Switzerland, etc.
'Spanish' => 45_000_000, # Spain
'Polish' => 38_000_000, # Poland
'Ukrainian' => 32_000_000, # Ukraine
'Romanian' => 24_000_000, # Romania, Moldova
'Dutch' => 22_000_000 # Netherlands, Belgium
},
'plot.type' => 'pie',
title => 'Top Languages in Europe',
autopct => '%1.1f%%',
},
{
data => {
'United States' => 86,
'United Kingdom' => 33,
'Germany' => 29,
'France' => 10,
'Japan' => 7,
'Israel' => 6,
},
title => 'Chem. Nobels: swap text positions',
'plot.type' => 'pie',
autopct => '%1.1f%%',
pctdistance => 1.25,
labeldistance => 0.6,
}
],
'input.file' => $tmp_filename,
execute => 0,
set_figwidth => 12,
ncols => 3,
});
plot
single, simple
plot({
'input.file' => $tmp_filename,
execute => 0,
'output.filename' => 'output.images/plot.single.png',
data => {
'sin(x)' => [
[@x], # x
[ map { sin($_) } @x ] # y
],
'cos(x)' => [
[@x], # x
[ map { cos($_) } @x ] # y
],
},
'plot.type' => 'plot',
title => 'simple plot',
set_xticks =>
"[-2 * $pi, -3 * $pi / 2, -$pi, -$pi / 2, 0, $pi / 2, $pi, 3 * $pi / 2, 2 * $pi"
. '], [r\'$-2\pi$\', r\'$-3\pi/2$\', r\'$-\pi$\', r\'$-\pi/2$\', r\'$0$\', r\'$\pi/2$\', r\'$\pi$\', r\'$3\pi/2$\', r\'$2\pi$\']',
'set.options' => { # set options overrides global settings
'sin(x)' => 'color="blue", linewidth=2',
'cos(x)' => 'color="red", linewidth=2'
}
});
which makes the following "plot" plot:
multiple sub-plots
my $pi = atan2( 0, -1 );
my @x = linspace( -2 * $pi, 2 * $pi, 100, 1 );
plot({
'input.file' => $tmp_filename,
execute => 0,
'output.filename' => 'output.images/plot.png',
plots => [
{ # plot 1
data => {
'sin(x)' => [
[@x], # x
[ map { sin($_) } @x ] # y
],
'cos(x)' => [
[@x], # x
[ map { cos($_) } @x ] # y
],
},
'plot.type' => 'plot',
title => 'simple plot',
set_xticks =>
"[-2 * $pi, -3 * $pi / 2, -$pi, -$pi / 2, 0, $pi / 2, $pi, 3 * $pi / 2, 2 * $pi"
. '], [r\'$-2\pi$\', r\'$-3\pi/2$\', r\'$-\pi$\', r\'$-\pi/2$\', r\'$0$\', r\'$\pi/2$\', r\'$\pi$\', r\'$3\pi/2$\', r\'$2\pi$\']',
'set.options' => { # set options overrides global settings
'sin(x)' => 'color="blue", linewidth=2',
'cos(x)' => 'color="red", linewidth=2'
},
set_xlim => "$x[0], $x[-1]", # set min and max as a string
},
{ # plot 2
data => {
'csc(x)' => [
[@x], # x
[ map { 1 / sin($_) } @x ] # y
],
'sec(x)' => [
[@x], # x
[ map { 1 / cos($_) } @x ] # y
],
},
'plot.type' => 'plot',
title => 'simple plot',
set_xticks =>
"[-2 * $pi, -3 * $pi / 2, -$pi, -$pi / 2, 0, $pi / 2, $pi, 3 * $pi / 2, 2 * $pi"
. '], [r\'$-2\pi$\', r\'$-3\pi/2$\', r\'$-\pi$\', r\'$-\pi/2$\', r\'$0$\', r\'$\pi/2$\', r\'$\pi$\', r\'$3\pi/2$\', r\'$2\pi$\']',
'set.options' => { # set options overrides global settings
'csc(x)' => 'color="purple", linewidth=2',
'sec(x)' => 'color="green", linewidth=2'
},
set_xlim => "$x[0], $x[-1]", # set min and max as a string
set_ylim => '-9,9',
},
],
ncols => 2,
set_figwidth => 12,
});
which makes
scatter
options
single, simple plot
multiple plots
plot({
'input.file' => $tmp_filename,
'output.file' => 'output.images/scatterplots.png',
execute => 0,
nrows => 2,
ncols => 3,
set_figheight => 8,
set_figwidth => 16,
suptitle => 'Scatterplot Examples', # applies to all
plots => [
{ # single-set scatter; no label
data => {
X => @e, # x-axis
Y => @b, # y-axis
Z => @a # color
},
title => '"Single Set Scatterplot: Random Distributions"',
color_key => 'Z',
'set.options' => 'marker = "v"'
, # arguments to ax.scatter: there's only 1 set, so "set.options" is a scalar
text => [ '100, 100, "text1"', '100, 100, "text2"', ],
'plot.type' => 'scatter',
},
{ # multiple-set scatter, labels are "X" and "Y"
data => {
X => { # 1st data set; label is "X"
A => @a, # x-axis
B => @b, # y-axis
},
W => { # 2nd data set; label is "Y"
A => generate_normal_dist( 100, 15, 210 ), # x-axis
B => generate_normal_dist( 100, 15, 210 ), # y-axis
}
},
'plot.type' => 'scatter',
title => 'Multiple Set Scatterplot',
'set.options' =>
{ # arguments to ax.scatter, for each set in data
X => 'marker = ".", color = "red"',
W => 'marker = "d", color = "green"'
},
},
{ # multiple-set scatter, labels are "X" and "Y"
data => { # 8th plot,
X => { # 1st data set; label is "X"
A => @e, # x-axis
B => @b, # y-axis
C => @a, # color
},
Y => { # 2nd data set; label is "Y"
A => generate_normal_dist( 100, 15, 210 ), # x-axis
B => generate_normal_dist( 100, 15, 210 ), # y-axis
C => generate_normal_dist( 100, 15, 210 ), # color
},
},
'plot.type' => 'scatter',
title => 'Multiple Set Scatter w/ colorbar',
'set.options' => { # arguments to ax.scatter, for each set in data
X => 'marker = "."', # diamond
Y => 'marker = "d"' # diamond
},
color_key => 'Z',
}
]
});
which makes the following figure:
violin
options
single, simple plot
plot({
'output.file' => 'output.images/single.violinplot.png',
data => { # simple hash
A => [ 55, @{$z} ],
E => [ @{$y} ],
B => [ 122, @{$z} ],
},
'plot.type' => 'violinplot',
title => 'Single Violin Plot: Specified Colors',
colors => { E => 'yellow', B => 'purple', A => 'green' },
'input.file' => $tmp_filename,
execute => 0,
});
which makes:
multiple plots
plot({
'input.file' => $tmp_filename,
execute => 0,
'output.file' => 'output.images/violin.png',
plots => [
{
data => {
E => @e,
B => @b
},
'plot.type' => 'violinplot',
title => 'Basic',
xlabel => 'xlabel',
set_figwidth => 12,
suptitle => 'Violinplot'
},
{
data => {
E => @e,
B => @b
},
'plot.type' => 'violinplot',
color => 'red',
title => 'Set Same Color for All',
},
{
data => {
E => @e,
B => @b
},
'plot.type' => 'violinplot',
colors => {
E => 'yellow',
B => 'black'
},
title => 'Color by Key',
},
{
data => {
E => @e,
B => @b
},
orientation => 'horizontal',
'plot.type' => 'violinplot',
colors => {
E => 'yellow',
B => 'black'
},
title => 'Horizontal orientation',
},
{
data => {
E => @e,
B => @b
},
whiskers => 0,
'plot.type' => 'violinplot',
colors => {
E => 'yellow',
B => 'black'
},
title => 'Whiskers off',
},
],
ncols => 3,
nrows => 2,
});
wide
options
single, simple plot
multiple plots
Advanced
Notes in Files
all files that can have notes with them, give notes about how the file was written. For example, SVG files have the following:
<dc:title>made/written by /mnt/ceph/dcondon/ui/gromacs/tut/dup.2puy/1.plot.gromacs.pl called using "plot" in /mnt/ceph/dcondon/perl5/perlbrew/perls/perl-5.42.0/lib/site_perl/5.42.0/x86_64-linux/Matplotlib/Simple.pm</dc:title>`
Speed
To improve speed, all data can be written into a single temp python3 file thus:
use File::Temp 'tempfile';
my ( $fh, $tmp_filename ) = tempfile( DIR => '/tmp', SUFFIX => '.py', UNLINK => 0 );
close $fh;
all files will be written to $tmp_filename; be sure to put execute => 0
plot({
data => {
Clinical => [
[
[@xw], # x
[@y] # y
],
[ [@xw], [ map { $_ + rand_between( -0.5, 0.5 ) } @y ] ],
[ [@xw], [ map { $_ + rand_between( -0.5, 0.5 ) } @y ] ]
],
HGI => [
[
[@xw], # x
[ map { 1.9 - 1.1 / $_ } @xw ] # y
],
[ [@xw], [ map { $_ + rand_between( -0.5, 0.5 ) } @y ] ],
[ [@xw], [ map { $_ + rand_between( -0.5, 0.5 ) } @y ] ]
]
},
'output.filename' => 'output.images/single.wide.png',
'plot.type' => 'wide',
color => {
Clinical => 'blue',
HGI => 'green'
},
title => 'Visualization of similar lines plotted together',
'input.file' => $tmp_filename,
execute => 0,
});
# the last plot should have C<< execute =E<gt> 1 >>
plot({
data => [
[
[@xw], # x
[@y] # y
],
[ [@xw], [ map { $_ + rand_between( -0.5, 0.5 ) } @y ] ],
[ [@xw], [ map { $_ + rand_between( -0.5, 0.5 ) } @y ] ]
],
'output.filename' => 'output.images/single.array.png',
'plot.type' => 'wide',
color => 'red',
title => 'Visualization of similar lines plotted together',
'input.file' => $tmp_filename,
execute => 1,
});