#!/usr/bin/perl -w =head1 NAME lalaim - Produce a LaTeX file with axis labels for an image. =head1 USE lalaim [options] left right [hlab] bot top [vlab] snhmt image.ext left: horizontal coordinate (floating point) of the left image edge. right: horizontal coordinate (floating point) of the right image edge. hlab: label for the horizontal axis, in LaTeX syntax. bot: vertical coordinate (floating point) of the bottom image edge. top: vertical coordinate (floating point) of the top image edge. vlab: label for the vertical axis, in LaTeX syntax. snhmt: suggested number of horizontal major ticks. image.ext: filename of the image. ext is taken to be anything after the final dot. The optimum number of major ticks is set by the ratio of the maximum horizontal label length to the image width. =head1 DESCRIPTION lalaim outputs a LaTeX file image.tex with a picture environment for labelling the axes of image.ext. The labelled image can then be included in a LaTeX document with \\input{image} assuming image.ext and image.tex are in the same directory. lalaim guesses at reasonable values for the start, end, and spacing of the ticks. left need not be less than right, and bot need not be less than top. =head1 OPTIONS -H: suppresses the horizontal numbers, although ticks will still be drawn. Implies -h. -V: suppresses the vertical numbers, although ticks will still be drawn. Implies -v. -h: suppresses the horizontal label. -v: suppresses the vertical label. -c color: Color to use for ticks. =cut use Getopt::Std; use POSIX qw(floor ceil); use strict; my $use = q { Use: lalaim [options] left right [hlab] bot top [vlab] image.ext left: horizontal coordinate (floating point) of the left image edge. right: horizontal coordinate (floating point) of the right image edge. hlab: label for the horizontal axis, in LaTeX syntax. bot: vertical coordinate (floating point) of the bottom image edge. top: vertical coordinate (floating point) of the top image edge. vlab: label for the vertical axis, in LaTeX syntax. snhmt: suggested number of horizontal major ticks. image.ext: filename of the image. ext is taken to be anything after the final dot. The optimum number of major ticks is set by the ratio of the maximum horizontal label length to the image width. }; # Given the start and end coordinates, and the preferred number of ticks, # returns the start and end tick values, the major tick spacing, and the number # of minor ticks between major ticks. sub reasonableticks { my ($sc, $ec, $pn) = @_; my $naivespc = abs($ec - $sc) / $pn; my $logns = 0.434294482 * log($naivespc); my $flogns = floor($logns); my $m = $logns - $flogns; my $M = 2; if($m <= 0.150515){ $M = 1; } elsif($m > 0.5){ $M = 5; } if($m > 0.8750612634){ $M = 10; } my $minorpermajor = 4; if($M == 2){ $minorpermajor = 1; } my $ts = $M * 10 ** $flogns; if($ec < $sc){ $ts = -$ts; } return ($ts * ceil($sc / $ts), $ts * floor($ec / $ts), $ts, $minorpermajor); } # print " sc\t ec\tpn | st\t et\tspacing\tminorpermajor\n"; # print "-" x 70; # print "\n"; # printf("%5.3g\t%5.3g\t% 2d | %5.3g\t%5.3g\t%5.3g\t% 2d\n", # -19.5, -2.3, 7, reasonableticks(-19.5, -2.3, 7)); # printf("%5.3g\t%5.3g\t% 2d | %5.3g\t%5.3g\t%5.3g\t% 2d\n", # -19.5, -2.3, 6, reasonableticks(-19.5, -2.3, 6)); # printf("%5.3g\t%5.3g\t% 2d | %5.3g\t%5.3g\t%5.3g\t% 2d\n", # -19.5, -2.3, 8, reasonableticks(-19.5, -2.3, 8)); # printf("%5.3g\t%5.3g\t% 2d | %5.3g\t%5.3g\t%5.3g\t% 2d\n", # 175, 110, 7, reasonableticks(175, 110, 7)); # printf("%5.3g\t%5.3g\t% 2d | %5.3g\t%5.3g\t%5.3g\t% 2d\n", # 175, 110, 6, reasonableticks(175, 110, 6)); # printf("%5.3g\t%5.3g\t% 2d | %5.3g\t%5.3g\t%5.3g\t% 2d\n", # 175, 110, 8, reasonableticks(175, 110, 8)); # printf("%5.3g\t%5.3g\t% 2d | %5.3g\t%5.3g\t%5.3g\t% 2d\n", # 0.0, 4.5, 8, reasonableticks(0.0, 4.5, 8)); # printf("%5.3g\t%5.3g\t% 2d | %5.3g\t%5.3g\t%5.3g\t% 2d\n", # 0.0, 4.5e-5, 8, reasonableticks(0.0, 4.5e-5, 8)); # printf("%5.3g\t%5.3g\t% 2d | %5.3g\t%5.3g\t%5.3g\t% 2d\n", # 170.0, 174.0, 8, reasonableticks(170.0, 174.0, 8)); sub get_bounding_box { my $imfn = shift; my $bbline = `grep -m 1 '^%%BoundingBox: ' $imfn`; chomp $bbline; my @bb = (); if($bbline =~ /^%%BoundingBox:\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/){ @bb = ($1, $2, $3, $4); } return @bb; } sub round { my $num = shift; my $floored = floor($num); return $num - $floored >= 0.5 ? $floored + 1 : $floored; } sub axis_label { my ($direction, $sc, $ec, $label, $lgth, $color, $pn, $majticklength, $width) = @_; my ($st, $et, $spacing, $minorpermajor) = reasonableticks($sc, $ec, $pn); my $minspac = $spacing / ($minorpermajor + 1); my $smint = $minspac * ceil($sc / $minspac); my $emint = $minspac * floor($ec / $minspac); my $tstart = $lgth * ($st - $sc) / ($ec - $sc); my $mints = $lgth * ($smint - $sc) / ($ec - $sc); my $tinc = $lgth * $spacing / ($ec - $sc); my $minincr = $tinc / ($minorpermajor + 1); my $xstart = $tstart; my $othxstart = $tstart; my $minxs = $mints; my $othminxs = $mints; my $ystart = 0; my $othystart = $width; my $minys = 0; my $othminys = $width; my $xincr = $tinc; my $yincr = 0; my $xmincr = $minincr; my $ymincr = 0; if($direction eq 'v'){ $ystart = $tstart; $xstart = 0; $othxstart = $width; $othystart = $tstart; $minys = $mints; $minxs = 0; $othminxs = $width; $othminys = $mints; $yincr = $tinc; $xincr = 0; $ymincr = $minincr; $xmincr = 0; } my $nmt = round(1 + ($et - $st) / $spacing); my $nmint = round(1 + ($emint - $smint) / $minspac); my $output = "{\\color{$color} %\n"; $output .= "\\thinlines%\n"; my $tickdir = $direction eq 'h' ? "0,1" : "1,0"; my $minticklength = 0.5 * $majticklength; $output .= "\\multiput($minxs,$minys)($xmincr,$ymincr){$nmint}{\\line("; $output .= "$tickdir){$minticklength}}%\n"; # Bot or left min ticks $output .= "\\thicklines%\n"; $output .= "\\multiput($xstart,$ystart)($xincr,$yincr){$nmt}{\\line("; $output .= "$tickdir){$majticklength}}%\n"; # Bot or left maj ticks $tickdir = $direction eq 'h' ? "0,-1" : "-1,0"; my $nlabdir = $direction eq 'h' ? 't' : 'r'; $output .= "\\multiput($othxstart,$othystart)($xincr,$yincr){$nmt}{\\line("; $output .= "$tickdir){$majticklength}}%\n"; # Top or right maj ticks $output .= "\\thinlines%\n"; $output .= "\\multiput($othminxs,$othminys)($xmincr,$ymincr){$nmint}"; $output .= "{\\line($tickdir){$minticklength}}%\n"; # Top or right min ticks $output .= "}%\n"; # End of color and ticks. my $lngestnlab = 0; for(my $i = 0; $i < $nmt; ++$i){ $output .= "\\put("; my $tpos = $tstart + $i * $tinc; if($direction eq 'h'){ $output .= "$tpos,$ystart"; } else{ $output .= "$xstart,$tpos"; } $output .= "){\\makebox(0,0)[$nlabdir]{\\strut{}"; my $nlab = $st + $i * $spacing; my $lngnlab = length($nlab); if($lngnlab > $lngestnlab){ # Keep track of the widest label. $lngestnlab = $lngnlab; } $output .= $st + $i * $spacing; if($direction eq 'v'){ $output .= " "; # Puts a space btw the number and the axis. } $output .= "}}%\n"; } $output .= "\\put("; # Axis label. if($direction eq 'v'){ $output .= -0.75 * $lngestnlab * $majticklength; $output .= ","; $output .= 0.5 * $lgth; # Center $output .= "){\\rotatebox{90}{\\makebox(0,0)[c]{\\strut{}$label}}}%\n"; } else{ $output .= 0.5 * $lgth; # Center $output .= ","; $output .= -1.5 * $majticklength; $output .= "){\\makebox(0,0)[c]{\\strut{}$label}}%\n"; } return $output; } our($opt_h, $opt_v, $opt_H, $opt_V, $opt_c); getopts('hvHVc:'); my $nohnums = $opt_H ? "y" : "n"; my $novnums = $opt_V ? "y" : "n"; my $nohlab = $opt_h ? "y" : "n"; my $novlab = $opt_v ? "y" : "n"; if($opt_H){ $nohlab = 'y'; } if($opt_V){ $novlab = 'y'; } my $color = $opt_c || "black"; # die "opt_h: $opt_h, color: $color, ARGV: @ARGV"; my $lft = shift; my $rgt = shift; my $hlab = ($nohlab eq 'y') ? '' : shift; my $bot = shift; my $top = shift; my $vlab = ($novlab eq 'y') ? '' : shift; my $snhmt = shift; my $imfn = shift or die $use; my $texfn = reverse $imfn; $texfn =~ s/^[^.]+\./xet./; $texfn = reverse $texfn; my ($bbllx, $bblly, $bburx, $bbury) = get_bounding_box($imfn); open(LTX, "> $texfn") or die "could not > $texfn"; print LTX "\\begin{picture}(0,0)%\n"; print LTX "\\includegraphics{$imfn}%\n"; print LTX "\\end{picture}%\n"; print LTX "\\begingroup\n"; print LTX "\\setlength{\\unitlength}{0.100bp}%\n"; my $hlen = 10 * ($bburx - $bbllx); my $vlen = 10 * ($bbury - $bblly); print LTX "\\begin{picture}($hlen,$vlen)(0,0)%\n"; print LTX "\\thicklines%\n"; print LTX "\\put(0,0){\\framebox($hlen,$vlen){}}%\n"; my $majticklength = sqrt(0.100 * $vlen * 240); print LTX axis_label('h', $lft, $rgt, $hlab, $hlen, $color, $snhmt, $majticklength, $vlen); print LTX axis_label('v', $bot, $top, $vlab, $vlen, $color, $snhmt * sqrt($vlen / $hlen), $majticklength, $hlen); print LTX "\\end{picture}%\n"; print LTX "\\endgroup\n"; print LTX "\\endinput\n"; close(LTX) or die "error closing > $texfn";