File Coverage

blib/lib/PGPLOT/Simple.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package PGPLOT::Simple;
2              
3 1     1   1147 use 5.008000;
  1         5  
  1         47  
4 1     1   13 use strict;
  1         2  
  1         33  
5 1     1   14 use warnings;
  1         2  
  1         35  
6              
7 1     1   6 use Exporter qw/import/;
  1         2  
  1         49  
8              
9 1     1   454 use PGPLOT;
  0            
  0            
10             use Carp qw/croak/;
11             use List::Util qw/min max/;
12             use List::MoreUtils qw/any none/;
13             use Scalar::Util qw/looks_like_number/;
14              
15             our %EXPORT_TAGS = (
16             'essential' => [qw(
17             set_begin set_end set_environment
18             set_viewport set_window set_box
19             set_active_panel set_range
20            
21             write_label write_text write_text_viewport
22            
23             draw_points draw_line draw_polyline
24             draw_polygon draw_rectangle draw_circle
25             draw_arrow draw_error_bars draw_function
26             draw_histogram
27            
28             move_pen
29             )],
30             'optional' => [qw(
31             set_color set_color_representation set_line_width
32             set_line_style set_character_height set_font
33             set_text_background set_fill_area_style set_hatching_style
34             set_arrow_style
35              
36             )],
37             'pgplot' => [ @PGPLOT::EXPORT ],
38             );
39              
40             our @EXPORT_OK = ();
41             our @EXPORT = ();
42              
43             Exporter::export_ok_tags('essential');
44             Exporter::export_ok_tags('optional');
45             Exporter::export_ok_tags('pgplot');
46              
47             our $VERSION = '0.05';
48              
49              
50             my $ATTR2SUB = {
51             font => \&set_font,
52             color => \&set_color,
53             width => \&set_line_width,
54             style => \&set_line_style,
55             fill => \&set_fill_area_style,
56             height => \&set_character_height,
57             background => \&set_text_background,
58             arrow_style => \&set_arrow_style,
59             hatching_style => \&set_hatching_style,
60             };
61              
62             my $PALLETE = {
63             Background => 0,
64             Foreground => 1,
65             Red => 2,
66             Green => 3,
67             Blue => 4,
68             Cyan => 5,
69             Magenta => 6,
70             Yellow => 7,
71             Orange => 8,
72             GreenYellow => 9,
73             GreenCyan => 10,
74             BlueCyan => 11,
75             BlueMagenta => 12,
76             RedMagenta => 13,
77             DarkGray => 14,
78             LightGray => 15,
79             };
80              
81             my $FONT = {
82             Normal => 1,
83             Roman => 2,
84             Italic => 3,
85             Script => 4,
86             };
87              
88             my $LINE_STYLE = {
89             FullLine => 1,
90             Dashed => 2,
91             DotDashDotDash => 3,
92             Dotted => 4,
93             DashDotDotDot => 5,
94             };
95              
96             my $TEXT_ALIGN = {
97             Left => 0.0,
98             Center => 0.5,
99             Right => 1.0,
100             };
101              
102             my $FILL_AREA_STYLE = {
103             Solid => 1,
104             Outline => 2,
105             Hatched => 3,
106             CrossHatched => 4,
107             };
108              
109             my $BOX_STYLE = {
110             Clean => -2,
111             Box => -1,
112             BoxCoord => 0,
113             BoxCoordAxes => 1,
114             BoxCoordAxesGrid => 2,
115             BoxXLog => 10,
116             BoxYLog => 20,
117             BoxXYLog => 30,
118             };
119              
120             my $ARROW_STYLE = {
121             Filled => 1,
122             Outline => 2,
123             };
124              
125              
126             ###############################################################
127             # OPEN, CLOSING, AND SELECTING DEVICES
128             ###############################################################
129              
130              
131             # Open a graphics device
132             sub set_begin {
133             my $args = shift;
134              
135             my $file = exists $args->{'file'} ? $args->{'file'} : "-/CPS";
136             # The device specification for the plot device
137             my $nxsub = exists $args->{'num_x_sub'} ? $args->{'num_x_sub'} : 1;
138             my $nysub = exists $args->{'num_y_sub'} ? $args->{'num_y_sub'} : 1;
139             # Number of X and Y subdivisions of the view surface
140             my $unit = 0; # This is ignored by the library
141            
142             my $status = pgbeg( $unit, $file, $nxsub, $nysub );
143              
144             return $status;
145             }
146              
147             # Closes all graphics devices
148             sub set_end {
149             pgend;
150             return;
151             }
152              
153             sub set_environment {
154             my $args = shift;
155              
156             croak "x_min, x_max, y_min, y_max parameters are required."
157             if any {! exists $args->{$_} } qw/x_min x_max y_min y_max/;
158              
159             my $x_min = $args->{'x_min'};
160             my $x_max = $args->{'x_max'};
161              
162             my $y_min = $args->{'y_min'};
163             my $y_max = $args->{'y_max'};
164              
165             my $justify = 0;
166             # Default don't justify the axes together
167             if ( exists $args->{'justify'} && $args->{'justify'} ne 0 ) {
168             $justify = 1;
169             }
170              
171             my $axes = $BOX_STYLE->{'BoxCoordAxes'};
172             # Default draw box and label it with coordinates and draw the coordinate axes
173             if ( exists $args->{'axes'} ) {
174             my $id = $args->{'axes'};
175            
176             if ( exists $BOX_STYLE->{ $id } ) {
177             $axes = $BOX_STYLE->{ $id };
178             # If the user provided a valid axes key
179             }
180             elsif ( looks_like_number $id && any { $id == $_ } (-2,-1,0,1,2,10,20,30) ) {
181             $axes = $id;
182             # If the user provided directly the axes code
183             }
184             else {
185             croak "Wrong axes parameter supplied.";
186             }
187             }
188              
189             pgsave; # Save current attributes
190              
191             set_attributes( $args ); # Design settings
192              
193             pgenv( $x_min, $x_max, $y_min, $y_max, $justify, $axes );
194              
195             pgunsa; # Restore previous attributes
196              
197             return;
198             }
199              
200              
201             ###############################################################
202             # WINDOWS AND VIEWPORTS
203             ###############################################################
204              
205              
206             # Set viewport
207             sub set_viewport {
208             my $args = shift;
209              
210             croak "x_left, x_right, y_bot, y_top parameters are required."
211             if any {! exists $args->{$_} } qw/x_left x_right y_bot y_top/;
212              
213             croak "Must provide a value between 0 and 1."
214             if any { !(
215             looks_like_number $args->{$_}
216             && $args->{$_} >= 0
217             && $args->{$_} <= 1
218             )
219             } qw/x_left x_right y_bot y_top/;
220              
221             my $x_left = $args->{'x_left'};
222             my $x_right = $args->{'x_right'};
223              
224             my $y_bot = $args->{'y_bot'};
225             my $y_top = $args->{'y_top'};
226              
227             pgsvp( $x_left, $x_right, $y_bot, $y_top );
228              
229             return;
230             }
231              
232             # Set window
233             sub set_window {
234             my $args = shift;
235              
236             croak "x_min, x_max, y_min, y_max parameters are required."
237             if any {! exists $args->{$_} } qw/x_min x_max y_min y_max/;
238              
239             my $x_min = $args->{'x_min'};
240             my $x_max = $args->{'x_max'};
241              
242             my $y_min = $args->{'y_min'};
243             my $y_max = $args->{'y_max'};
244              
245             pgswin( $x_min, $x_max, $y_min, $y_max );
246              
247             return;
248             }
249              
250             # Switch to a different panel on the view surface
251             sub set_active_panel {
252             my $args = shift;
253            
254             croak "x_index and y_index parameters are required."
255             if any {! exists $args->{$_} } qw/x_index y_index/;
256              
257             my $ix = $args->{'x_index'};
258             my $iy = $args->{'y_index'};
259              
260             pgpanl( $ix, $iy );
261              
262             return;
263             }
264              
265             # Choose axis limits
266             sub set_range {
267             my $args = shift;
268            
269             croak "x1, x2, x_low and x_high parameters are required."
270             if any{! exists $args->{$_} } qw/x1 x2 x_low x_high/;
271              
272             my $x1 = $args->{'x1'};
273             my $x2 = $args->{'x2'};
274            
275             my $x_lo = $args->{'x_low' };
276             my $x_hi = $args->{'x_high'};
277              
278             pgrnge($x1, $x2, $x_lo, $x_hi );
279            
280             return;
281             }
282              
283              
284             ###############################################################
285             # AXES, BOXES AND LABELS
286             ###############################################################
287              
288              
289             # Draw frame and write (DD) HH MM SS.S labelling
290             sub set_box {
291             my $args = shift;
292              
293             my $x_opt = exists $args->{'x_style'} ? $args->{'x_style'} : 'ABCGZHON';
294             my $y_opt = exists $args->{'y_style'} ? $args->{'y_style'} : 'ABCGN';
295              
296             my $x_tick = exists $args->{'x_tick'} ? $args->{'x_tick'} : 0.0;
297             my $y_tick = exists $args->{'y_tick'} ? $args->{'y_tick'} : 0.0;
298              
299             my $n_x_sub = exists $args->{'n_x_sub'} ? $args->{'n_x_sub'} : 0;
300             my $n_y_sub = exists $args->{'n_y_sub'} ? $args->{'n_y_sub'} : 0;
301              
302             pgsave; # Save current attributes
303              
304             set_attributes( $args ); # Design settings
305              
306             pgtbox( $x_opt, $x_tick, $n_x_sub, $y_opt, $y_tick, $n_y_sub );
307              
308             pgunsa; # Restore previous attributes
309              
310             return;
311             }
312              
313             # Write labels for x-axis, y-axis, and top of plot
314             sub write_label {
315             my $args = shift;
316              
317             my $x = exists $args->{'x'} ? $args->{'x'} : 'X';
318             my $y = exists $args->{'y'} ? $args->{'y'} : 'Y';
319             my $title = exists $args->{'title'} ? $args->{'title'} : 'Untitled';
320              
321             pgsave; # Save current attributes
322              
323             set_attributes( $args ); # Design settings
324              
325             pglab( $x, $y, $title );
326              
327             pgunsa; # Restore previous attributes
328              
329             return;
330             }
331              
332             sub write_text_viewport {
333             my $args = shift;
334              
335             croak "Must provide a string to write."
336             unless exists $args->{'string'};
337            
338             my $text = $args->{'string'};
339             my $side = exists $args->{'side'} ? $args->{'side'} : 'BR';
340             # Default to bottom right positioned
341             my $disp = exists $args->{'displace'} ? $args->{'displace'} : 1;
342             # Default displacement relative to the viewport
343             my $coord = exists $args->{'coord'} ? $args->{'coord'} : 1;
344             # Default location of the character string along the specified edge of the viewport
345             my $fjust = get_align( $args->{'justify'} );
346              
347             pgsave; # Save current attributes
348              
349             set_attributes( $args ); # Design settings
350              
351             pgmtxt( $side, $disp, $coord, $fjust, $text );
352            
353             pgunsa; # Restore previous attributes
354              
355             return;
356             }
357              
358              
359             ###############################################################
360             # PRIMITIVES
361             ###############################################################
362              
363              
364             # LINES
365             #
366              
367             # Draw a polyline (curve defined by line-segments)
368             sub draw_polyline {
369             my $args = shift;
370              
371             croak "x and y parameters are required."
372             if any {! exists $args->{$_} } qw/x y/;
373              
374             my $x = $args->{'x'};
375             my $y = $args->{'y'};
376              
377             pgsave; # Save current attributes
378              
379             set_attributes( $args ); # Design settings
380              
381             # Line size
382             my $size = scalar @$x;
383              
384             pgline( $size, $x, $y );
385              
386             pgunsa; # Restore previous attributes
387              
388             return;
389             }
390              
391             # Move pen (change current pen position)
392             sub move_pen {
393             my $args = shift;
394              
395             my ($x, $y) = ();
396              
397             if ( exists $args->{'x'} && exists $args->{'y'} ) {
398             $x = $args->{'x'};
399             $y = $args->{'y'};
400              
401             pgmove( $x, $y ); # Move pen to position
402             }
403              
404             pgqpos( $x, $y ); # Return current pen position
405              
406             return ($x, $y);
407             }
408              
409             # Draw a line from the current pen position to a point
410             sub draw_line {
411             my $args = shift;
412              
413             croak "x and y parameters are required."
414             if any {! exists $args->{$_} } qw/x y/;
415            
416             my $x = $args->{'x'};
417             my $y = $args->{'y'};
418              
419             pgsave; # Save current attributes
420              
421             set_attributes( $args ); # Design settings
422              
423             pgdraw( $x, $y );
424              
425             pgunsa; # Restore previous attributes
426              
427             return;
428             }
429              
430             # POLYGONS AND FILLED AREAS
431             #
432              
433             # Draw a polygon, using fill-area attributes
434             sub draw_polygon {
435             my $args = shift;
436              
437             croak "x and y parameters are required."
438             if any {! exists $args->{$_} } qw/x y/;
439              
440             my $x = $args->{'x'};
441             my $y = $args->{'y'};
442              
443             pgsave; # Save current attributes
444              
445             set_attributes( $args ); # Design settings
446              
447             # Number of points
448             my $num = scalar @$x;
449              
450             pgpoly( $num, $x, $y );
451              
452             pgunsa; # Restore previous attributes
453              
454             return;
455             }
456              
457             # Draw a circle, using fill-area attributes
458             sub draw_circle {
459             my $args = shift;
460              
461             croak "x, y and radius parameters are required."
462             if any {! exists $args->{$_} } qw/x y radius/;
463              
464             my $x = $args->{'x'};
465             my $y = $args->{'y'};
466             my $radius = $args->{'radius'};
467              
468             pgsave; # Save current attributes
469              
470             set_attributes( $args ); # Design settings
471              
472             pgcirc( $x, $y, $radius );
473              
474             pgunsa; # Restore previous attributes
475              
476             return;
477             }
478              
479             # Draw a rectangle, using fill-area attibutes
480             sub draw_rectangle {
481             my $args = shift;
482              
483             croak "x1,y1,x2 and y2 parameters are required."
484             if any {! exists $args->{$_} } qw/x1 x2 y1 y2/;
485              
486             my $x1 = $args->{'x1'};
487             my $x2 = $args->{'x2'};
488             my $y1 = $args->{'y1'};
489             my $y2 = $args->{'y2'};
490              
491             pgsave; # Save current attributes
492              
493             set_attributes( $args ); # Design settings
494              
495             pgrect( $x1, $x2, $y1, $y2 );
496              
497             pgunsa; # Restore previous attributes
498              
499             return;
500             }
501              
502              
503             # GRAPH MARKERS
504             #
505              
506             # Draw several graph markers.
507             sub draw_points {
508             my $args = shift;
509              
510             croak "x, and y parameters are required."
511             if any {! exists $args->{$_} } qw/x y/;
512              
513             my $x = $args->{'x'};
514             my $y = $args->{'y'};
515             my $symbol = exists $args->{'symbol'} ? $args->{'symbol'} : -1;
516              
517             pgsave; # Save current attributes
518              
519             set_attributes( $args ); # Design settings
520              
521             # How many
522             my $num = scalar @$x;
523              
524             pgpt( $num, $x, $y, $symbol );
525              
526             pgunsa; # Restore previous attributes
527              
528             return;
529             }
530              
531              
532             # TEXT
533             #
534              
535             # Write text at arbitrary position and angle
536             sub write_text {
537             my $args = shift;
538              
539             croak "x,y and string parameters are required."
540             if any {! exists $args->{$_} } qw/x y string/;
541              
542             my $x = $args->{'x'};
543             my $y = $args->{'y'};
544             my $string = $args->{'string'};
545              
546             my $align = get_align( $args->{'align'} );
547             my $angle = get_angle( $args->{'angle'} );
548              
549             pgsave; # Save current attributes
550              
551             set_attributes( $args ); # Design settings
552              
553             pgptxt( $x, $y, $angle, $align, $string );
554              
555             pgunsa; # Restore previous attributes
556            
557             return;
558             }
559              
560              
561             # ARROWS
562             #
563              
564             sub draw_arrow {
565             my $args = shift;
566              
567             croak "x1,y1,x2 and y2 parameters are required."
568             if any {! exists $args->{$_} } qw/x1 x2 y1 y2/;
569              
570             my $x1 = $args->{'x1'};
571             my $x2 = $args->{'x2'};
572             my $y1 = $args->{'y1'};
573             my $y2 = $args->{'y2'};
574              
575             pgsave; # Save current attributes
576              
577             set_attributes( $args ); # Design settings
578              
579             pgarro( $x1, $y1, $x2, $y2 );
580              
581             pgunsa; # Restore previous attributes
582              
583             return;
584             }
585              
586              
587             ###############################################################
588             # ATTRIBUTES
589             ###############################################################
590              
591              
592             sub set_attributes {
593             my $args = shift;
594              
595             for my $attr ( keys %$ATTR2SUB ) {
596             if ( exists $args->{ $attr } ) {
597             &{ $ATTR2SUB->{ $attr } }( $args->{ $attr } );
598             }
599             }
600              
601             return;
602             }
603              
604              
605             # COLOR
606             #
607              
608             sub set_color {
609             my $id = shift;
610            
611             my $color = $PALLETE->{'Foreground'}; # Default color
612              
613             if (defined $id) {
614             if ( exists $PALLETE->{ $id } ) {
615             $color = $PALLETE->{ $id };
616             # If the user provided a valid color key
617             }
618             elsif ( looks_like_number $id && $id >= 0 && $id <= 255 ) {
619             $color = $id;
620             # If the user provided directly the color code
621             }
622             else {
623             croak "Must provide a valid color.";
624             }
625             }
626              
627             pgsci( $color ); # PGPLOT call setting color
628            
629             return;
630             }
631              
632             sub set_color_representation {
633             my $args = shift;
634              
635             croak "code, red, green and blue parameters are required."
636             if any { !(
637             looks_like_number $args->{$_}
638             && exists $args->{$_}
639             )
640             } qw/code red green blue/;
641              
642             my $code = $args->{'code'};
643             my $red = $args->{'red'};
644             my $green = $args->{'green'};
645             my $blue = $args->{'blue'};
646              
647             # Data range validation
648             croak "Code index value out of range"
649             unless ( $code >= 0 && $code <= 255 );
650              
651             croak "Any of the rgb values supplied is out of range."
652             if any { !( $_ >= 0 && $_ <= 1 ) }
653             ($red, $green, $blue);
654              
655             pgscr( $code, $red, $green, $blue );
656              
657             return;
658             }
659              
660              
661             # LINE ATTRIBUTES
662             #
663              
664             sub set_line_width {
665             my $num = shift;
666              
667             my $width = 2; # Default width
668              
669             if ( defined $num ) {
670             if ( looks_like_number $num && $num >= 1 && $num <= 201 ) {
671             $width = $num;
672             }
673             else {
674             croak "Must provide a valid integer number for line width.";
675             }
676             }
677              
678             pgslw( $width ); # PGPLOT call setting line width
679              
680             return;
681             }
682              
683             sub set_line_style {
684             my $id = shift;
685              
686             my $style = $LINE_STYLE->{'Solid'}; # Default style
687            
688             if (defined $id) {
689             if ( exists $LINE_STYLE->{ $id } ) {
690             $style = $LINE_STYLE->{ $id };
691             # If the user provided a valid line style
692             }
693             elsif ( looks_like_number $id && $id >= 1 && $id <= 5 ) {
694             $style = $id;
695             # If the user provided directly the style code
696             }
697             else {
698             croak "Must provide a valid style.";
699             }
700             }
701              
702             pgsls( $style ); # PGPLOT call setting line style
703            
704             return;
705             }
706              
707              
708             # TEXT AND MARKER ATTRIBUTES
709             #
710              
711             sub set_character_height {
712             my $value = shift;
713              
714             my $height = 1.0; # Default height
715              
716             if (defined $value) {
717             if ( looks_like_number $value ) {
718             $height = $value;
719             }
720             else {
721             croak "Must provide a real number for character height.";
722             }
723             }
724              
725             pgsch( $height ); # PGPLOT call setting line height
726              
727             return;
728             }
729              
730             sub set_font {
731             my $id = shift;
732              
733             my $font = $FONT->{'Normal'}; # Default font
734              
735             if (defined $id) {
736             if ( exists $FONT->{ $id } ) {
737             $font = $FONT->{ $id };
738             # If the user provided a valid font type
739             }
740             elsif ( looks_like_number $id && $id >= 1 && $id <= 4 ) {
741             $font = $id;
742             # If the user provided directly the font type
743             }
744             else {
745             croak "Must provide a valid font.";
746             }
747             }
748              
749             pgscf( $font ); # PGPLOT call setting font type
750              
751             return;
752             }
753              
754             sub set_text_background {
755             my $id = shift;
756            
757             my $color = -1; # Default transparent color
758              
759             if (defined $id) {
760             if ( exists $PALLETE->{ $id } ) {
761             $color = $PALLETE->{ $id };
762             # If the user provided a valid color key
763             }
764             elsif ( looks_like_number $id && $id >= -1 && $id <= 255 ) {
765             $color = $id;
766             # If the user provided directly the color code
767             }
768             else {
769             croak "Must provide a valid color.";
770             }
771             }
772              
773             pgstbg( $color ); # PGPLOT call setting text background color
774            
775             return;
776             }
777              
778              
779             # FILL-AREA ATTRIBUTES
780             #
781              
782             sub set_fill_area_style {
783             my $id = shift;
784              
785             my $style = $FILL_AREA_STYLE->{'Solid'}; # Default text alignment
786              
787             if (defined $id) {
788             if ( exists $FILL_AREA_STYLE->{ $id } ) {
789             $style = $FILL_AREA_STYLE->{ $id };
790             # If the user provided a valid fill style
791             }
792             elsif ( looks_like_number $id && $id >= 1 && $id <= 4 ) {
793             $style = $id;
794             # If the user provided directly the fill style
795             }
796             else {
797             croak "Must provide a valid fill style.";
798             }
799             }
800              
801             pgsfs( $style );
802              
803             return;
804             }
805              
806             sub set_hatching_style {
807             my $args = shift;
808              
809             my $angle = 45.0;
810             my $sepn = 1.0;
811             my $phase = 0.0;
812             # Default values
813              
814             if ( exists $args->{'angle'} ) {
815             my $value = $args->{'angle'};
816             if ( looks_like_number $value && $value >= 0 && $value <= 360 ) {
817             $angle = $value;
818             }
819             else {
820             croak "Must provide a valid angle value.";
821             }
822             }
823             if ( exists $args->{'spacing'} ) {
824             my $value = $args->{'spacing'};
825             if ( looks_like_number $value && $value >= 0 && $value <= 100 ) {
826             $sepn = $value;
827             }
828             else {
829             croak "Must provide a valid spacing value.";
830             }
831             }
832             if ( exists $args->{'phase'} ) {
833             my $value = $args->{'phase'};
834             if ( looks_like_number $value && $value >= 0 && $value <= 1 ) {
835             $phase = $value;
836             }
837             else {
838             croak "Must provide a valid phase value.";
839             }
840             }
841              
842             pgshs( $angle, $sepn, $phase );
843              
844             return;
845             }
846              
847              
848             # ARROW ATTRIBUTES
849             #
850              
851             sub set_arrow_style {
852             my $args = shift;
853              
854             my $fs = $ARROW_STYLE->{'Filled'};
855             my $angle = 45;
856             my $barb = 0.3;
857              
858             if( exists $args->{'fill'} ) {
859             my $id = $args->{'fill'};
860             if( exists $ARROW_STYLE->{ $id } ) {
861             $fs = $ARROW_STYLE->{ $id };
862             # If the user provided a valid fill style
863             }
864             elsif ( looks_like_number $id && $id >= 1 && $id <= 2 ) {
865             $fs = $id;
866             # If the user provided directly the fill style
867             }
868             else {
869             croak "Must provide a valid fill style.";
870             }
871             }
872             if( exists $args->{'arrow_angle'} ) {
873             my $value = $args->{'arrow_angle'};
874             if ( looks_like_number $value && $value >= 0 && $value <= 360 ) {
875             my $angle = $value;
876             }
877             else {
878             croak "Must provide a valid arrow angle";
879             }
880             }
881             if( exists $args->{'arrow_barb'} ) {
882             my $value = $args->{'arrow_barb'};
883             if ( looks_like_number $value && $value >= 0 && $value <= 1 ) {
884             my $angle = $value;
885             }
886             else {
887             croak "Must provide a valid arrow barb";
888             }
889             }
890              
891             pgsah( $fs, $angle, $barb );
892              
893             return;
894             }
895              
896              
897             ###############################################################
898             # XY PLOTS
899             ###############################################################
900              
901              
902             # ERROR BARS
903             #
904              
905             # Horizontal / Vertical error bars
906             sub draw_error_bars {
907             my $args = shift;
908              
909             croak "Must provide either (x1,x2,y) or (y1,y2,x) parameters."
910             if none { exists $args->{$_} } qw/x y/;
911              
912             # Error bars terminal, undef mean proportional of the length of the bar
913              
914             pgsave; # Save current attributes
915              
916             set_attributes( $args ); # Design settings
917              
918             if( exists $args->{'y'} ) {
919             croak "x1, x2 and y parameters are required."
920             if any {! exists $args->{$_} } qw/x1 x2 y terminal/;
921              
922             my $x1 = $args->{'x1'};
923             my $x2 = $args->{'x2'};
924             my $y = $args->{'y'};
925             my $terminals = $args->{'terminal'};
926             my $num = scalar @$y;
927            
928             pgerrx( $num, $x1, $x2, $y, $terminals );
929             }
930             elsif ( exists $args->{'x'} ) {
931             croak "y1, y2, and x parameters are required."
932             if any {! exists $args->{$_} } qw/y1 y2 x terminal/;
933              
934             my $y1 = $args->{'y1'};
935             my $y2 = $args->{'y2'};
936             my $x = $args->{'x'};
937             my $terminals = $args->{'terminal'};
938             my $num = scalar @$x;
939              
940             pgerry( $num, $x, $y1, $y2, $terminals );
941             }
942              
943             pgunsa; # Restore previous attributes
944              
945             return;
946             }
947              
948              
949             # CURVES DEFINED BY FUNCTIONS
950             #
951              
952             sub draw_function {
953             my ($by, $args) = @_;
954              
955             croak "Must define by x, y or xy."
956             if none { $by eq $_ } qw/x y xy/;
957              
958             my $flag = exists $args->{'flag'} ? $args->{'flag'} : 1;
959             # Default plotted in the current window and viewport
960              
961             pgsave; # Save current attributes
962              
963             set_attributes( $args ); # Design settings
964              
965             if ($by eq 'x') { # Function defined by X = F(Y)
966             croak "fy, num, min and max parameters are required."
967             if any {! exists $args->{$_} } qw/fy num min max/;
968              
969             my $fy = $args->{'fy'};
970             my $num = $args->{'num'};
971             my $min = $args->{'min'};
972             my $max = $args->{'max'};
973              
974             pgfunx( $fy, $num, $min, $max, $flag );
975             }
976             elsif ($by eq 'y') { # Function defined by Y = F(X)
977             croak "fx, num, min and max parameters are required."
978             if any {! exists $args->{$_} } qw/fx num min max/;
979            
980             my $fx = $args->{'fx'};
981             my $num = $args->{'num'};
982             my $min = $args->{'min'};
983             my $max = $args->{'max'};
984              
985             pgfuny( $fx, $num, $min, $max, $flag );
986             }
987             else { # Function defined by X = F(T), Y = G(T)
988             croak "fx, fy, num, min and max parameters are required."
989             if any {! exists $args->{$_} } qw/fx fy num min max/;
990              
991             my $fx = $args->{'fx'};
992             my $fy = $args->{'fy'};
993             my $num = $args->{'num'};
994             my $min = $args->{'min'};
995             my $max = $args->{'max'};
996              
997             pgfunt( $fx, $fy, $num, $min, $max, $flag );
998             }
999              
1000             pgunsa; # Restore previous attributes
1001              
1002             return;
1003             }
1004              
1005              
1006             # HISTOGRAMS
1007             #
1008              
1009             sub draw_histogram {
1010             my $args = shift;
1011              
1012             croak "data parameter is required."
1013             unless exists $args->{'data'};
1014              
1015             pgsave; # Save current attributes
1016              
1017             set_attributes( $args ); # Design settings
1018              
1019             my $data = $args->{'data'};
1020             my $flag = exists $args->{'flag'} ? $args->{'flag'} : 1;
1021             # Default plotted in the current window and viewport
1022             my @temp = grep { defined } @$data;
1023             # This if done because List::Util's die with arrays that may contain undef
1024             my $min = exists $args->{'min'} ? $args->{'min'} : min @temp;
1025             my $max = exists $args->{'max'} ? $args->{'max'} : max @temp;
1026             my $num = scalar @$data;
1027             my $nbin = exists $args->{'nbin'} ? $args->{'nbin'} : $num % 400;
1028              
1029             pghist( $num, $data, $min, $max, $nbin, $flag );
1030              
1031             pgunsa; # Restore previous attributes
1032              
1033             return;
1034             }
1035              
1036              
1037             ###############################################################
1038             # MISC
1039             ###############################################################
1040              
1041              
1042             sub get_align {
1043             my $id = shift;
1044              
1045             my $align = $TEXT_ALIGN->{'Left'}; # Default text alignment
1046              
1047             if (defined $id) {
1048             if ( exists $TEXT_ALIGN->{ $id } ) {
1049             $align = $TEXT_ALIGN->{ $id };
1050             # If the user provided a valid text alignment
1051             }
1052             elsif ( looks_like_number $id && any { $id == $_ } (0, 0.5, 1) ) {
1053             $align = $id;
1054             # If the user provided directly the text alignment
1055             }
1056             else {
1057             croak "Must provide a valid align or justification value.";
1058             }
1059             }
1060              
1061             return $align;
1062             }
1063              
1064             sub get_angle {
1065             my $degree = shift;
1066              
1067             my $angle = 0; # Default angle
1068              
1069             if (defined $degree) {
1070             if ( looks_like_number $degree && $degree >= 0 && $degree <= 360 ) {
1071             $angle = $degree;
1072             # If the user provided a valid degree
1073             }
1074             else {
1075             croak "Must provide a valid angle degree value.";
1076             }
1077             }
1078              
1079             return $angle;
1080             }
1081              
1082              
1083             1;
1084              
1085             __END__