# 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;
    bar({
	   'output.file'     => '/tmp/gospel.word.counts.png',
	   data              => {
		  Matthew => 18345,
		  Mark    => 11304,
		  Luke    => 19482,
		  John    => 15635,
	   }
    });

A nore complete (and slightly faster execution):

    use Matplotlib::Simple;
    plt({
	   'output.file'     => '/tmp/gospel.word.counts.png',
	   'plot.type'       => 'bar',
	   data              => {
		  Matthew => 18345,
		  Mark    => 11304,
		  Luke    => 19482,
		  John    => 15635,
	   }
    });

<img width="651" height="491" alt="gospel word counts" src="https://github.com/user-attachments/assets/a008dece-2e34-47bf-af0f-8603709f7d52" />

# Multiple Plots

Having a `plots` argument as an array lets the module know to create subplots:

    use Matplotlib::Simple 'plt';
    plt({
    	'output.file'	=> '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:

<img width="651" height="424" alt="pies" src="https://github.com/user-attachments/assets/49d3e28b-f897-4b01-9e72-38afa12fa538" />

`bar`, `barh`, `boxplot`, `hexbin`, `hist`, `hist2d`, `imshow`, `pie`, `plot`, `scatter`, and `violinplot` all match the methods in matplotlib itself.


# 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 'plt';
    plt({
	    'output.file'			=> '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`, `fh` are all specific to `MatPlotLib::Simple`.
<img width="651" height="491" alt="single barplot" src="https://github.com/user-attachments/assets/eae009a8-5571-4608-abdb-1016e3cff5fd" />

### multiple plots

    plt({
	    fh                  => $fh,
	    execute				   => 0,
	    'output.file'	=> '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	
    				},
		    	},
	    		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'
    		},	
		    { # 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:

<img width="2678" height="849" alt="barplots" src="https://github.com/user-attachments/assets/6d87d13b-dabd-485d-92f7-1418f4acc65b" />

## 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

    use Matplotlib::Simple 'barplot';
    barplot({
    	'output.file' => 'output.images/single.boxplot.png',
    	data              => {                                     # simple hash
    		E => [ 55,    @{$x}, 160 ],
    		B => [ @{$y}, 140 ],

    		#		A => @a
    	},
    	title        => 'Single Box Plot: Specified Colors',
    	colors       => { E => 'yellow', B => 'purple' },
    	fh           => $fh,
    	execute      => 0,
    });

which makes the following image:

<img width="651" height="491" alt="single boxplot" src="https://github.com/user-attachments/assets/19870fa2-fe36-4513-8cbb-23da3a0cf686" />

### multiple plots

    plt({
    	'output.file' => 'output.images/boxplot.png',
    	execute           => 0,
    	fh => $fh,
    	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:

<img width="1230" height="1211" alt="boxplot" src="https://github.com/user-attachments/assets/7e32e394-86fc-49e7-ad97-f48fd82fc8b0" />

## Colored Table

### options

### Single, simple plot

the bond dissociation energy table can be plotted:

    # https://labs.chem.ucsb.edu/zakarian/armen/11---bonddissociationenergy.pdf and https://chem.libretexts.org/Bookshelves/Physical_and_Theoretical_Chemistry_Textbook_Maps/Supplemental_Modules_(Physical_and_Theoretical_Chemistry)/Chemical_Bonding/Fundamentals_of_Chemical_Bonding/Bond_Energies
    my %bond_dissociation = (
    	Br =>  {
    	  Br =>  193
    	},
    	C  =>  {
    		Br =>  276,	C  =>  347,	Cl =>  339,	F   => 485,	H  =>  413,	I  =>  240,
    		N  =>  305,	O  =>  358,	S  =>  259
    	},
    	Cl =>  {
    		Br =>  218,	Cl =>  239
    	},
    	F =>   {
    		I => 280, Br =>  237, Cl  => 253, F   => 154
    	},
    	H  =>  {
    		Br =>  363,	Cl =>  427,	F  =>  565,	H   => 432,	I   => 295
    	},
    	I  =>  {
    		Br  => 175,	Cl =>  208,	I  =>  149
    	},
    	N  =>  {
    		Br =>  243,	Cl  => 200,	F   => 272,	H  =>  391,	N  =>  160, O  =>  201
    	},
    	O =>   {
    		Cl =>  203, F  =>  190,	H  =>  467,	I  =>  234,	O  =>  146
    	},
    	S  =>  {
    		Br => 218,	Cl => 253,	F  => 327,	H  => 347,	S  => 266
    	},
    	Si => {
    		C  => 360, H  => 393, O  => 452,	Si => 340
    	}
    );

and the plot itself:

    colored_table({
    	'cblabel'     => 'kJ/mol',
    	'col.labels'  => ['H', 'F', 'Cl', 'Br', 'I'],
    	data          => \%bond_dissociation,
    	execute       => 0,
    	fh            => $fh,
    	mirror        => 1,
    	'output.file' => 'output.images/single.tab.png',
    	'row.labels'  => ['H', 'F', 'Cl', 'Br', 'I'],
    	'show.numbers'=> 1,
    	set_title     => 'Bond Dissociation Energy'
    });

which makes the following image:

<img width="584" height="491" alt="single tab" src="https://github.com/user-attachments/assets/d890830b-a502-4d51-b118-20aeae0473e8" />

### Multiple Plots

    plt({
    	'output.file' => 'output.images/tab.multiple.png',
    	execute       => 0,
    	fh            => $fh,
    	plots         => [
    		{
    			data          => \%bond_dissociation,
    			'output.file' => '/tmp/single.bonds.svg',
    			'plot.type'   => 'colored_table',
    			set_title     => 'No other options'
    		},
    		{
    			data          => \%bond_dissociation,
    			cblabel       => 'Average Dissociation Energy (kJ/mol)',
    			'col.labels'  => ['H', 'C', 'N', 'O', 'F', 'Si', 'S', 'Cl', 'Br', 'I'],
    			mirror        => 1,
    			'output.file' => '/tmp/single.bonds.svg',
    			'plot.type'   => 'colored_table',
    			'row.labels'  => ['H', 'C', 'N', 'O', 'F', 'Si', 'S', 'Cl', 'Br', 'I'],
    			'show.numbers'=> 1,
    			set_title     => 'Showing numbers and mirror with defined order'
    		},
    		{
    			data          => \%bond_dissociation,
    			cblabel       => 'Average Dissociation Energy (kJ/mol)',
    			'col.labels'  => ['H', 'C', 'N', 'O', 'F', 'Si', 'S', 'Cl', 'Br', 'I'],
    			mirror        => 1,
    			'output.file' => '/tmp/single.bonds.svg',
    			'plot.type'   => 'colored_table',
    			'row.labels'  => ['H', 'C', 'N', 'O', 'F', 'Si', 'S', 'Cl', 'Br', 'I'],
    			'show.numbers'=> 1,
    			set_title     => 'Set undefined color to white',
    			'undef.color' => 'white'
    		}
    	],
    	ncols         => 3,
    	set_figwidth  => 14,
    	suptitle      => 'Colored Table options'
    });

which makes the following plot:

<img width="1410" height="491" alt="tab multiple" src="https://github.com/user-attachments/assets/be836742-cc5b-4618-a0c8-a0ee57856eb1" />

## hexbin

Plot a hash of arrays as a hexbin
see https://matplotlib.org/stable/api/_as_gen/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

    plt({
    	data	=> {
    		E	=> generate_normal_dist(100, 15, 3*210),
    		B	=> generate_normal_dist(85, 15, 3*210)
    	},
    	'output.file'	=> 'output.images/single.hexbin.png',
    	'plot.type'	=> 'hexbin',
    	set_figwidth => 12,
    	title			=> 'Simple Hexbin',
    });

which makes the following plot:
<img width="1208" height="491" alt="single hexbin" src="https://github.com/user-attachments/assets/129c41cd-2d7d-43de-978a-2b9c441b8939" />
### multiple plots

    plt({
    	fh => $fh,
    	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:
<img width="2409" height="3211" alt="hexbin" src="https://github.com/user-attachments/assets/0b23a0cb-8f9a-43fb-8da1-0debee13d540" />

## 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

    use Matplotlib::Simple 'hist';
	
    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 );

    hist({
    	fh => $fh,
    	execute           => 0,
    	'output.file' => 'output.images/single.hist.png',
    	data              => {
	    	E => @e,
	    	B => @b,
	    	A => @a,
    	}
    });

which makes the following simple plot:

<img width="651" height="491" alt="single hist" src="https://github.com/user-attachments/assets/fafcf787-6c4f-4998-88c4-77a15d878fa6" />

### multiple plots

    plt({
    	fh => $fh,
    	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,
    });

<img width="1511" height="491" alt="histogram" src="https://github.com/user-attachments/assets/b13b4cc8-6e64-40b0-913d-6a5886cee0db" />

Make a 2-D histogram from a hash of arrays

## hist2d

### single, simple plot
    plt({
    	'output.file' => 'output.images/single.hist2d.png',
    	data              => {
    		E => @e,
    		B => @b
    	},
    	'plot.type'  => 'hist2d',
    	title        => 'title',
    	execute      => 0,
    	fh => $fh,
    });
makes the following image:

<img width="650" height="491" alt="single hist2d" src="https://github.com/user-attachments/assets/86480c77-7b8f-4bfa-b5d8-71f82830260f" />

the range for the density min and max is reported to stdout

### options

| Option | Description | Example |
| -------- | ------- | ------- |
|`cb_logscale`| make the colorbar log-scale | `cb_logscale => 1` |
|`cmap`| color map for coloring # "gist_rainbow" by default |  |
|'cmax', `cmin`| All bins that has count < *cmin* or > *cmax* will not be displayed|
|  'density'|  density : bool, default: False|
|  'key.order'|  define the keys in an order (an array reference)
| 'logscale' |    # logscale, an array of axes that will get log scale
|'show.colorbar'| self-evident, 0 or 1 | `show.colorbar` => 1|
|'vmax'| When using scalar data and no explicit *norm*, *vmin* and *vmax* define the data range that the colormap cover |
|'vmin' | # When using scalar data and no explicit *norm*, *vmin* and *vmax* define the data range that the colormap cover |
|'xbins'| # default 15
|'xmin', 'xmax',|
|'ymin', 'ymax',|
|'ybins' |  default 15 | 

### multiple plots
    plt({
    	fh => $fh,
    	execute           => 1,
    	ncols             => 3,
    	nrows             => 3,
    	suptitle          => 'Types of hist2d plots: all of the data is identical',
    	plots => [
    		{
    			data => {
    			X => $x,    # x-axis
    			Y => $y,    # y-axis
    			},
    			'plot.type' => 'hist2d',
    			title       => 'Simple hist2d',
    		},
    		{
    			data => {
    				X => $x,    # x-axis
    				Y => $y,    # y-axis
    			},
    			'plot.type' => 'hist2d',
    			title       => 'cmap = terrain',
    			cmap        => 'terrain'
    		},
    		{
    			cmap => 'ocean',
    			data => {
    				X => $x,    # x-axis
    				Y => $y,    # y-axis
    			},
    			'plot.type' => 'hist2d',
    			title => 'cmap = ocean and set colorbar range with vmin/vmax',
    			set_figwidth => 15,
    			vmin         => -2,
    			vmax         => 14
    		},
    		{
    			data => {
    				X => $x,    # x-axis
    				Y => $y,    # y-axis
    			},
    			'plot.type' => 'hist2d',
    			title       => 'density = True',
    			cmap        => 'terrain',
    			density     => 'True'
    		},
    		{
    			data => {
    				X => $x,    # x-axis
    				Y => $y,    # y-axis
    			},
    			'plot.type' => 'hist2d',
    			title       => 'key.order flips axes',
    			cmap        => 'terrain',
    			'key.order' => [ 'Y', 'X' ]
    		},
    		{
    			cb_logscale => 1,
    			data => {
    				X => $x,    # x-axis
    				Y => $y,    # y-axis
    			},
    			'plot.type' => 'hist2d',
    			title       => 'cb_logscale = 1',
    		},
    		{
    			cb_logscale => 1,
    			data => {
    				X => $x,    # x-axis
    				Y => $y,    # y-axis
    			},
    			'plot.type' => 'hist2d',
    			title       => 'cb_logscale = 1 with vmax set',
    			vmax        => 2.1,
    			vmin        => 1
    		},
    		{
    			data => {
    				X => $x,    # x-axis
    				Y => $y,    # y-axis
    			},
    			'plot.type'     => 'hist2d',
    			'show.colorbar' => 0,
    			title           => 'no colorbar',
    		},
    		{
    			data => {
    				X => $x,    # x-axis
    				Y => $y,    # y-axis
    			},
    			'plot.type'     => 'hist2d',
    			title           => 'xbins = 9',
    			xbins           => 9
    		},
    	],
    	'output.file' => 'output.images/hist2d.png',
    });
makes the following image:

<img width="1510" height="491" alt="hist2d" src="https://github.com/user-attachments/assets/3d6becd3-44f3-4511-8b0f-eae39bc325fa" />

## 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);
    	}
    }
    plt({
    	data              => \@imshow_data,
    	execute           => 0,
       fh => $fh,
    	'output.file' => '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:

<img width="599" height="491" alt="imshow single" src="https://github.com/user-attachments/assets/3fa4ffe6-4817-4133-9c91-b68099400377" />

### multiple plots

    plt({
    	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,
      fh              => $fh,
    	'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:

<img width="2416" height="1811" alt="imshow multiple" src="https://github.com/user-attachments/assets/091acccb-151c-47ca-82cc-99c19d2bff91" />

## pie

### options

### single, simple plot

    plt({
    	'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',
    	fh           => $fh,
    	execute      => 0,
    });

which makes the image:

<img width="469" height="491" alt="single pie" src="https://github.com/user-attachments/assets/a0bc3212-d013-463a-9be6-f96829ac7dba" />

### multiple plots

    plt({
    	'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,
    		}
    	],
    	fh => $fh,
    	execute      => 0,
       set_figwidth  => 12,
    	ncols        => 3,
    });

<img width="1210" height="444" alt="pie" src="https://github.com/user-attachments/assets/4c44d300-fd84-49bc-9a32-b73af54286cf" />

## plot

plot either a hash of arrays or an array of arrays

### single, simple

data can be given as a hash, where the hash key is the label:

    plt({
    	fh => $fh,
    	execute           => 0,
    	'output.file' => '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'
    	}
    });

or as an array of arrays:

    plt({
    	fh => $fh,
    	execute           => 0,
    	'output.file' => 'output.images/plot.single.arr.png',
    	data              => [
    		[
    			[@x],                     # x
    			[ map { sin($_) } @x ]    # y
    		],
    		[
    		 	[@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; indices match data array
    		'color="blue", linewidth=2, label = "sin(x)"', # labels aren't added automatically when using array here
    		'color="red",  linewidth=2, label = "cos(x)"'
    	],
    });

both of which make the following "plot" plot:

<img width="651" height="491" alt="plot single" src="https://github.com/user-attachments/assets/6cbd6aad-c464-4703-b962-b420ec08bb66" />

### multiple sub-plots

which makes

    my $epsilon = 10**-7;
    my (%set_opt, %d);
    my $i = 0;
    foreach my $interval (
    	[-2*$pi, -$pi],
    	[-$pi, 0],
    	[0, $pi],
    	[$pi, 2*$pi]
    ) {
    	my @th = linspace($interval->[0] + $epsilon, $interval->[1] - $epsilon, 99, 0);
    	@{ $d{csc}{$i}[0] } = @th;
    	@{ $d{csc}{$i}[1] } = map { 1/sin($_) } @th;
    	@{ $d{cot}{$i}[0] } = @th;
    	@{ $d{cot}{$i}[1] } = map { cos($_)/sin($_) } @th;
    	if ($i == 0) {
    		$set_opt{csc}{$i} = 'color = "red", label = "csc(θ)"';
    		$set_opt{cot}{$i} = 'color = "violet", label = "cot(θ)"';
    	} else {
    		$set_opt{csc}{$i} = 'color = "red"';
    		$set_opt{cot}{$i} = 'color = "violet"';
    	}
    	$i++;
    }
    $i = 0;
    foreach my $interval (
    	[-2 * $pi, -1.5 * $pi],
    	[-1.5*$pi, -0.5*$pi],
    	[-0.5*$pi, 0.5 * $pi],
    	[0.5 * $pi, 1.5 * $pi],
    	[1.5 * $pi, 2 * $pi]
    ) {
    	my @th = linspace($interval->[0] + $epsilon, $interval->[1] - $epsilon, 99, 0);
    	@{ $d{sec}{$i}[0] } = @th;
    	@{ $d{sec}{$i}[1] } = map { 1/cos($_) } @th;
    	if ($i == 0) {
    		$set_opt{sec}{$i} = 'color = "blue", label = "sec(θ)"';
    		$set_opt{tan}{$i} = 'color = "green", label = "tan(θ)"';
    	} else {
    		$set_opt{sec}{$i} = 'color = "blue"';
    		$set_opt{tan}{$i} = 'color = "green"';
    	}
    	@{ $d{tan}{$i}[0] } = @th;
    	@{ $d{tan}{$i}[1] } = map { sin($_)/cos($_) } @th;
    	$i++;
    }
    mkdir 'svg' unless -d 'svg';
    my $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$\']';
    my ($min, $max) = (-9,9);
    plt({
    	fh => $fh,
    	execute           => 0,
    	'output.file' => 'output.images/plots.png',
    	plots         => [
    	{ # sin
    		data          => {
    			'sin(θ)' => [
    				[@x],
    				[map {sin($_)} @x]
    			]
    		},
    		'plot.type'   => 'plot',
    		'set.options' => {
    			'sin(θ)' => 'color = "orange"'
    		},
    		set_xticks    => $xticks,
    		set_xlim      => "-2*$pi, 2*$pi",
    		xlabel        => 'θ',
    		ylabel        => 'sin(θ)',
    	},
    	{ # sin
    		data          => {
    			'cos(θ)' => [
    				[@x],
    				[map {cos($_)} @x]
    			]
    		},
    		'plot.type'   => 'plot',
    		'set.options' => {
    			'cos(θ)' => 'color = "black"'
    		},
    		set_xticks    => $xticks,
    		set_xlim      => "-2*$pi, 2*$pi",
    		xlabel        => 'θ',
    		ylabel        => 'cos(θ)',
    	},
    	{ # csc
    		data          => $d{csc},
    		'plot.type'   => 'plot',
    		'set.options' => $set_opt{csc},
    		set_xticks    => $xticks,
    		set_xlim      => "-2*$pi, 2*$pi",
    		set_ylim      => "$min,$max",
    		'show.legend' => 0,
    		vlines        => [ # asymptotes
    			"-2*$pi, $min, $max, color = 'gray', linestyle = 'dashed'",
    			"-$pi, $min, $max, color = 'gray', linestyle = 'dashed'",
    			"0, $min, $max, color = 'gray', linestyle = 'dashed'",
    			"$pi, $min, $max, color = 'gray', linestyle = 'dashed'",
    			"2*$pi, $min, $max, color = 'gray', linestyle = 'dashed'",
    		],
    		xlabel        => 'θ',
    		ylabel        => 'csc(θ)',
    	},
    	{ # sec
    		data          => $d{sec},
    		'plot.type'   => 'plot',
    		'set.options' => $set_opt{sec},
    		set_xticks    => $xticks,
    		set_xlim      => "-2*$pi, 2*$pi",
    		set_ylim      => "$min,$max",
    		'show.legend' => 0,
    		vlines        => [ # asymptotes
    			"-1.5*$pi, $min, $max, color = 'gray', linestyle = 'dashed'",
    			"-.5*$pi, $min, $max, color = 'gray', linestyle = 'dashed'",
    			".5*$pi, $min, $max, color = 'gray', linestyle = 'dashed'",
    			"1.5*$pi, $min, $max, color = 'gray', linestyle = 'dashed'",
    #			"2*$pi, $min, $max, color = 'gray', linestyle = 'dashed'",
    		],
    		xlabel        => 'θ',
    		ylabel        => 'sec(θ)',
    	},
    		{ # csc
    		data          => $d{cot},
    		'plot.type'   => 'plot',
    		'set.options' => $set_opt{cot},
    		set_xticks    => $xticks,
    		set_xlim      => "-2*$pi, 2*$pi",
    		set_ylim      => "$min,$max",
    		'show.legend' => 0,
    		vlines        => [ # asymptotes
    			"-2*$pi, $min, $max, color = 'gray', linestyle = 'dashed'",
    			"-$pi, $min, $max, color = 'gray', linestyle = 'dashed'",
    			"0, $min, $max, color = 'gray', linestyle = 'dashed'",
    			"$pi, $min, $max, color = 'gray', linestyle = 'dashed'",
    			"2*$pi, $min, $max, color = 'gray', linestyle = 'dashed'",
    		],
    		xlabel        => 'θ',
    		ylabel        => 'cot(θ)',
    	},
    	{ # sec
    		data          => $d{tan},
    		'plot.type'   => 'plot',
    		'set.options' => $set_opt{tan},
    		set_xticks    => $xticks,
    		set_xlim      => "-2*$pi, 2*$pi",
    		set_ylim      => "$min,$max",
    		'show.legend' => 0,
    		vlines        => [ # asymptotes
    			"-1.5*$pi, $min, $max, color = 'gray', linestyle = 'dashed'",
    			"-.5*$pi, $min, $max, color = 'gray', linestyle = 'dashed'",
    			".5*$pi, $min, $max, color = 'gray', linestyle = 'dashed'",
    			"1.5*$pi, $min, $max, color = 'gray', linestyle = 'dashed'",
    #			"2*$pi, $min, $max, color = 'gray', linestyle = 'dashed'",
    		],
    		xlabel        => 'θ',
    		ylabel        => 'tan(θ)',
    	},
    	], # end
    	ncols        => 2,
    	nrows        => 3,
    	set_figwidth => 8,
    	suptitle     => 'Basic Trigonometric Functions'
    });

<img width="811" height="491" alt="plots" src="https://github.com/user-attachments/assets/0bdd0744-c1bb-4c4a-9482-b3de3f2d4fc2" />

## scatter

### single, simple plot
    scatter({
    	fh            => $fh,
    	data          => {
    		X => [@x],
    		Y => [map {sin($_)} @x]
    	},
    	execute       => 0,
    	'output.file' => 'output.images/single.scatter.png',
    });

makes the following image:

<img width="651" height="491" alt="single scatter" src="https://github.com/user-attachments/assets/c45d9922-23e0-4f85-8306-aa7fca400328" />

### options



### multiple plots

    plt({
    	fh => $fh,
    	'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:

<img width="1610" height="461" alt="scatterplots" src="https://github.com/user-attachments/assets/b8a90f9f-acb3-4cf2-a423-6ad18686ab8c" />

## violin

plot a hash of array refs as violins

### options

| Option | Description | Example |
| -------- | ------- | -------
|`color`| # a hash, where keys are the keys in data, and values are colors, e.g. X => 'blue'
|`colors`| match sets | `colors       => { E => 'yellow', B => 'purple', A => 'green' }`|
|`key.order`| determine key order display on x-axis|
|`log`|    # if set to > 1, the y-axis will be logarithmic
|`orientation`|'vertical', 'horizontal'}, default: 'vertical'|

### single, simple plot

    plt({
    	'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' },
    	fh => $fh,
    	execute      => 0,
    });

which makes:

<img width="651" height="491" alt="single violinplot" src="https://github.com/user-attachments/assets/989650fd-c947-45b0-91c8-c7f71c075cf3" />

### multiple plots

    plt({
    	fh                => $fh,
    	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,
    });

<img width="1211" height="491" alt="violin" src="https://github.com/user-attachments/assets/248df5e4-fd57-45d6-96da-956af0a7dbfb" />

## 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;
    my $fh = File::Temp->new( DIR => '/tmp', SUFFIX => '.py', UNLINK => 0 );
	
all files will be written to `$fh->filename`; be sure to put `execute => 0` unless you want the file to be run, which is the last step.

    plt({
        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.file' => 'output.images/single.wide.png',
        'plot.type'       => 'wide',
        color             => {
            Clinical => 'blue',
            HGI      => 'green'
        },
        title        => 'Visualization of similar lines plotted together',
        fh => $fh,
        execute      => 0,
    });
    # the last plot should have `execute => 1`
    plt({
        data => [
            [
                [@xw],    # x
                [@y]      # y
            ],
            [ [@xw], [ map { $_ + rand_between( -0.5, 0.5 ) } @y ] ],
            [ [@xw], [ map { $_ + rand_between( -0.5, 0.5 ) } @y ] ]
        ],
        'output.file' => 'output.images/single.array.png',
        'plot.type'       => 'wide',
        color             => 'red',
        title             => 'Visualization of similar lines plotted together',
        fh                => $fh,
        execute           => 1,
    });
