axestype.pm
上传用户:shbosideng
上传日期:2013-05-04
资源大小:1555k
文件大小:21k
源码类别:

SNMP编程

开发平台:

C/C++

  1. #==========================================================================
  2. #    Copyright (c) 1995-1998 Martien Verbruggen
  3. #--------------------------------------------------------------------------
  4. #
  5. # Name:
  6. # GIFgraph::axestype.pm
  7. #
  8. # $Id: axestype.pm,v 1.1.1.1 2002/02/26 10:16:37 oetiker Exp $
  9. #
  10. #==========================================================================
  11. package GIFgraph::axestype;
  12. use strict;
  13.  
  14. use GIFgraph;
  15. use GIFgraph::legend;
  16. use GIFgraph::utils qw(:all);
  17. @GIFgraph::axestype::ISA = qw( GIFgraph::legend GIFgraph );
  18. my %Defaults = (
  19.  
  20. # Set the length for the 'short' ticks on the axes.
  21.  
  22. tick_length => 4,
  23.  
  24. # Do you want ticks to span the entire width of the graph?
  25.  
  26. long_ticks => 0,
  27.  
  28. # Number of ticks for the y axis
  29.  
  30. y_tick_number => 5,
  31. x_tick_number => undef, # CONTRIB Scott Prahl
  32.  
  33. # Skip every nth label. if 1 will print every label on the axes,
  34. # if 2 will print every second, etc..
  35.  
  36. x_label_skip => 1,
  37. y_label_skip => 1,
  38. # Do we want ticks on the x axis?
  39. x_ticks => 1,
  40. x_all_ticks => 0,
  41. # Where to place the x and y labels
  42. x_label_position => 3/4,
  43. y_label_position => 1/2,
  44. # vertical printing of x labels
  45. x_labels_vertical => 0,
  46.  
  47. # Draw axes as a box? (otherwise just left and bottom)
  48.  
  49. box_axis => 1,
  50.  
  51. # Use two different axes for the first and second dataset. The first
  52. # will be displayed using the left axis, the second using the right
  53. # axis. You cannot use more than two datasets when this option is on.
  54.  
  55. two_axes => 0,
  56.  
  57. # Print values on the axes?
  58.  
  59. x_plot_values  => 1,
  60. y_plot_values  => 1,
  61.  
  62. # Space between axis and text
  63.  
  64. axis_space => 4,
  65.  
  66. # Do you want bars to be drawn on top of each other, or side by side?
  67.  
  68. overwrite  => 0,
  69. # Draw the zero axis in the graph in case there are negative values
  70. zero_axis => 0,
  71. # Draw the zero axis, but do not draw the bottom axis, in case
  72. # box-axis == 0
  73. # This also moves the x axis labels to the zero axis
  74. zero_axis_only => 0,
  75. # Format of the numbers on the x and y axis
  76. y_number_format => undef,
  77. x_number_format => undef, # CONTRIB Scott Prahl
  78. );
  79. {
  80.  
  81. # PUBLIC
  82. sub plot($) # (@data)
  83. {
  84. my $self = shift;
  85. my $data = shift;
  86.  
  87. $self->check_data($data);
  88. $self->init_graph($self->{graph});
  89. $self->plot_legend($self->{graph});
  90. $self->setup_coords($data);
  91. $self->draw_text($self->{graph});
  92. $self->draw_axes($self->{graph}, $data);
  93. $self->draw_ticks($self->{graph}, $data);
  94. $self->draw_data($self->{graph}, $data);
  95. return $self->{graph}->gif
  96. }
  97. sub set_x_label_font($) # (fontname)
  98. {
  99. my $self = shift;
  100. $self->{xlf} = shift;
  101. $self->set( 
  102. xlfw => $self->{xlf}->width,
  103. xlfh => $self->{xlf}->height,
  104. );
  105. }
  106. sub set_y_label_font($) # (fontname)
  107. {
  108. my $self = shift;
  109. $self->{ylf} = shift;
  110. $self->set( 
  111. ylfw => $self->{ylf}->width,
  112. ylfh => $self->{ylf}->height,
  113. );
  114. }
  115. sub set_x_axis_font($) # (fontname)
  116. {
  117. my $self = shift;
  118. $self->{xaf} = shift;
  119. $self->set( 
  120. xafw => $self->{xaf}->width,
  121. xafh => $self->{xaf}->height,
  122. );
  123. }
  124. sub set_y_axis_font($) # (fontname)
  125. {
  126. my $self = shift;
  127. $self->{yaf} = shift;
  128. $self->set( 
  129. yafw => $self->{yaf}->width,
  130. yafh => $self->{yaf}->height,
  131. );
  132. }
  133. # PRIVATE
  134. # called on construction, by new
  135. # use inherited defaults
  136.  
  137. sub initialise()
  138. {
  139. my $self = shift;
  140.  
  141. $self->SUPER::initialise();
  142.  
  143. my $key;
  144. foreach $key (keys %Defaults) 
  145. {
  146. $self->set( $key => $Defaults{$key} );
  147. }
  148.  
  149. $self->set_x_label_font(GD::gdSmallFont);
  150. $self->set_y_label_font(GD::gdSmallFont);
  151. $self->set_x_axis_font(GD::gdTinyFont);
  152. $self->set_y_axis_font(GD::gdTinyFont);
  153. }
  154.  
  155. # inherit check_data from GIFgraph
  156.  
  157. sub setup_coords($)
  158. {
  159. my $s = shift;
  160. my $data = shift;
  161. # Do some sanity checks
  162. $s->{two_axes} = 0 if ( $s->{numsets} != 2 || $s->{two_axes} < 0 );
  163. $s->{two_axes} = 1 if ( $s->{two_axes} > 1 );
  164. delete $s->{y_label2} unless ($s->{two_axes});
  165. # Set some heights for text
  166. $s->set( tfh => 0 ) unless ( $s->{title} );
  167. $s->set( xlfh => 0 ) unless ( $s->{x_label} );
  168. if ( ! $s->{y1_label} && $s->{y_label} ) 
  169. {
  170. $s->{y1_label} = $s->{y_label};
  171. }
  172. $s->set( ylfh1 => $s->{y1_label} ? 1 : 0 );
  173. $s->set( ylfh2 => $s->{y2_label} ? 1 : 0 );
  174. $s->set( xafh => 0, xafw => 0 ) unless ($s->{x_plot_values}); 
  175. $s->set( yafh => 0, yafw => 0 ) unless ($s->{y_plot_values});
  176. $s->{x_axis_label_height} = $s->get_x_axis_label_height($data);
  177. my $lbl = ($s->{xlfh} ? 1 : 0) + ($s->{xafh} ? 1 : 0);
  178. # calculate the top and bottom of the bounding box for the graph
  179. $s->{bottom} = 
  180. $s->{gify} - $s->{b_margin} - 1 -
  181. ( $s->{xlfh} ? $s->{xlfh} : 0 ) -
  182. ( $s->{x_axis_label_height} ? $s->{x_axis_label_height} : 0) -
  183. ( $lbl ? $lbl * $s->{text_space} : 0 );
  184. $s->{top} = $s->{t_margin} +
  185. ( $s->{tfh} ? $s->{tfh} + $s->{text_space} : 0 );
  186. $s->{top} = $s->{yafh}/2 if ( $s->{top} == 0 );
  187.  
  188. $s->set_max_min($data);
  189. # Create the labels for the y_axes, and calculate the max length
  190. $s->create_y_labels();
  191. $s->create_x_labels(); # CONTRIB Scott Prahl
  192. # calculate the left and right of the bounding box for the graph
  193. my $ls = $s->{yafw} * $s->{y_label_len}[1];
  194. $s->{left} = $s->{l_margin} +
  195.  ( $ls ? $ls + $s->{axis_space} : 0 ) +
  196.  ( $s->{ylfh1} ? $s->{ylfh} + $s->{text_space} : 0 );
  197. $ls = $s->{yafw} * $s->{y_label_len}[2] if $s->{two_axes};
  198. $s->{right} = $s->{gifx} - $s->{r_margin} - 1 -
  199.   $s->{two_axes} * (
  200.   ( $ls ? $ls + $s->{axis_space} : 0 ) +
  201.   ( $s->{ylfh2} ? $s->{ylfh} + $s->{text_space} : 0 )
  202.   );
  203. # CONTRIB Scott Prahl
  204. # make sure that we can generate valid x tick marks
  205. undef($s->{x_tick_number}) if $s->{numpoints} < 2;
  206. undef($s->{x_tick_number}) if (
  207. !defined $s->{x_max} || 
  208. !defined $s->{x_min} ||
  209. $s->{x_max} == $s->{x_min}
  210. );
  211.  
  212. # calculate the step size for x data
  213. # CONTRIB Changes by Scott Prahl
  214. if (defined $s->{x_tick_number})
  215. {
  216. my $delta = ($s->{right}-$s->{left})/($s->{x_max}-$s->{x_min});
  217. $s->{x_offset} = 
  218. ($s->{true_x_min} - $s->{x_min}) * $delta + $s->{left};
  219. $s->{x_step} = 
  220. ($s->{true_x_max} - $s->{true_x_min}) * $delta/$s->{numpoints};
  221. }
  222. else
  223. {
  224. $s->{x_step} = ($s->{right} - $s->{left})/($s->{numpoints} + 2);
  225. $s->{x_offset} = $s->{left};
  226. }
  227.  
  228. # get the zero axis level
  229. my $dum;
  230. ($dum, $s->{zeropoint}) = $s->val_to_pixel(0, 0, 1);
  231. # Check the size
  232. die "Vertical Gif size too small"
  233. if ( ($s->{bottom} - $s->{top}) <= 0 );
  234. die "Horizontal Gif size too small"
  235. if ( ($s->{right} - $s->{left}) <= 0 );
  236.  
  237. # More sanity checks
  238. $s->{x_label_skip} = 1  if ( $s->{x_label_skip} < 1 );
  239. $s->{y_label_skip} = 1  if ( $s->{y_label_skip} < 1 );
  240. $s->{y_tick_number} = 1 if ( $s->{y_tick_number} < 1 );
  241. }
  242. sub create_y_labels
  243. {
  244. my $s = shift;
  245. $s->{y_label_len}[1] = 0;
  246. $s->{y_label_len}[2] = 0;
  247. my $t;
  248. foreach $t (0 .. $s->{y_tick_number})
  249. {
  250. my $a;
  251. foreach $a (1 .. ($s->{two_axes} + 1))
  252. {
  253. my $label = 
  254. $s->{y_min}[$a] +
  255. $t *
  256. ($s->{y_max}[$a] - $s->{y_min}[$a])/$s->{y_tick_number};
  257. $s->{y_values}[$a][$t] = $label;
  258. if (defined $s->{y_number_format})
  259. {
  260. if (ref $s->{y_number_format} eq 'CODE')
  261. {
  262. $label = &{$s->{y_number_format}}($label);
  263. }
  264. else
  265. {
  266. $label = sprintf($s->{y_number_format}, $label);
  267. }
  268. }
  269. my $len = length($label);
  270. $s->{y_labels}[$a][$t] = $label;
  271. ($len > $s->{y_label_len}[$a]) and 
  272. $s->{y_label_len}[$a] = $len;
  273. }
  274. }
  275. }
  276. # CONTRIB Scott Prahl
  277. sub create_x_labels
  278. {
  279. my $s = shift;
  280. return unless defined($s->{x_tick_number});
  281. $s->{x_label_len} = 0;
  282. my $t;
  283. foreach $t (0..$s->{x_tick_number})
  284. {
  285. my $label =
  286. $s->{x_min} +
  287. $t * ($s->{x_max} - $s->{x_min})/$s->{x_tick_number};
  288. $s->{x_values}[$t] = $label;
  289. if (defined $s->{x_number_format})
  290. {
  291. if (ref $s->{x_number_format} eq 'CODE')
  292. {
  293. $label = &{$s->{x_number_format}}($label);
  294. }
  295. else
  296. {
  297. $label = sprintf($s->{x_number_format}, $label);
  298. }
  299. }
  300. my $len = length($label);
  301. $s->{x_labels}[$t] = $label;
  302. ($len > $s->{x_label_len}) and $s->{x_label_len} = $len;
  303. }
  304. }
  305. sub get_x_axis_label_height
  306. {
  307. my $s = shift;
  308. my $data = shift;
  309. return $s->{xafh} unless $s->{x_labels_vertical};
  310. my $len = 0;
  311. my $labels = $data->[0];
  312. my $label;
  313. foreach $label (@$labels)
  314. {
  315. my $llen = length($label);
  316. ($llen > $len) and $len = $llen;
  317. }
  318. return $len * $s->{xafw}
  319. }
  320.  
  321. # inherit open_graph from GIFgraph
  322.  
  323. sub draw_text($) # GD::Image
  324. {
  325. my $s = shift;
  326. my $g = shift;
  327.  
  328. # Title
  329. if ($s->{tfh}) 
  330. {
  331. my $tx = 
  332. $s->{left} + 
  333. ($s->{right} - $s->{left})/2 - 
  334. length($s->{title}) * $s->{tfw}/2;
  335. my $ty = $s->{top} - $s->{text_space} - $s->{tfh};
  336. $g->string($s->{tf}, $tx, $ty, $s->{title}, $s->{tci});
  337. }
  338. # X label
  339. if ($s->{xlfh}) 
  340. {
  341. my $tx = 
  342. $s->{left} +
  343. $s->{x_label_position} * ($s->{right} - $s->{left}) - 
  344. $s->{x_label_position} * length($s->{x_label}) * $s->{xlfw};
  345. my $ty = $s->{gify} - $s->{xlfh} - $s->{b_margin};
  346. $g->string($s->{xlf}, $tx, $ty, $s->{x_label}, $s->{lci});
  347. }
  348. # Y labels
  349. if ($s->{ylfh1}) 
  350. {
  351. my $tx = $s->{l_margin};
  352. my $ty = 
  353. $s->{bottom} -
  354. $s->{y_label_position} * ($s->{bottom} - $s->{top}) +
  355. $s->{y_label_position} * length($s->{y1_label}) * $s->{ylfw};
  356. $g->stringUp($s->{ylf}, $tx, $ty, $s->{y1_label}, $s->{lci});
  357. }
  358. if ( $s->{two_axes} && $s->{ylfh2} ) 
  359. {
  360. my $tx = $s->{gifx} - $s->{ylfh} - $s->{r_margin};
  361. my $ty = 
  362. $s->{bottom} -
  363. $s->{y_label_position} * ($s->{bottom} - $s->{top}) +
  364. $s->{y_label_position} * length($s->{y2_label}) * $s->{ylfw};
  365. $g->stringUp($s->{ylf}, $tx, $ty, $s->{y2_label}, $s->{lci});
  366. }
  367. }
  368.  
  369. sub draw_axes($) # GD::Image
  370. {
  371. my $s = shift;
  372. my $g = shift;
  373. my $d = shift;
  374. my ($l, $r, $b, $t) = 
  375. ( $s->{left}, $s->{right}, $s->{bottom}, $s->{top} );
  376.  
  377. if ( $s->{box_axis} ) 
  378. {
  379. $g->rectangle($l, $t, $r, $b, $s->{fgci});
  380. }
  381. else
  382. {
  383. $g->line($l, $t, $l, $b, $s->{fgci});
  384. $g->line($l, $b, $r, $b, $s->{fgci}) 
  385. unless ($s->{zero_axis_only});
  386. $g->line($r, $b, $r, $t, $s->{fgci}) 
  387. if ($s->{two_axes});
  388. }
  389. if ($s->{zero_axis} or $s->{zero_axis_only})
  390. {
  391. my ($x, $y) = $s->val_to_pixel(0, 0, 1);
  392. $g->line($l, $y, $r, $y, $s->{fgci});
  393. }
  394. }
  395. #
  396. # Ticks and values for y axes
  397. #
  398. sub draw_y_ticks($$) # GD::Image, @data
  399. {
  400. my $s = shift;
  401. my $g = shift;
  402. my $d = shift;
  403. #
  404. # Ticks and values for y axes
  405. #
  406. my $t;
  407. foreach $t (0 .. $s->{y_tick_number}) 
  408. {
  409. my $a;
  410. foreach $a (1 .. ($s->{two_axes} + 1)) 
  411. {
  412. my $value = $s->{y_values}[$a][$t];
  413. my $label = $s->{y_labels}[$a][$t];
  414. my ($x, $y) = $s->val_to_pixel(0, $value, $a);
  415. #my ($x, $y) = $s->val_to_pixel( 
  416. # ($a-1) * ($s->{numpoints} + 2), 
  417. # $value, 
  418. # $a 
  419. #);
  420. $x = ($a == 1) ? $s->{left} : $s->{right};
  421. if ($s->{long_ticks}) 
  422. {
  423. $g->line( 
  424. $x, $y, 
  425. $x + $s->{right} - $s->{left}, $y, 
  426. $s->{fgci} 
  427. ) unless ($a-1);
  428. else 
  429. {
  430. $g->line( 
  431. $x, $y, 
  432. $x + (3 - 2 * $a) * $s->{tick_length}, $y, 
  433. $s->{fgci} 
  434. );
  435. }
  436. next 
  437. if ( $t % ($s->{y_label_skip}) || ! $s->{y_plot_values} );
  438. $x -=
  439. (2-$a) * length($label) * $s->{yafw} + 
  440. (3 - 2 * $a) * $s->{axis_space};
  441. $y -= $s->{yafh}/2;
  442. $g->string($s->{yaf}, $x, $y, $label, $s->{alci});
  443. }
  444. }
  445. }
  446. #
  447. # Ticks and values for x axes
  448. #
  449. sub draw_x_ticks($$) # GD::Image, @data
  450. {
  451. my $s = shift;
  452. my $g = shift;
  453. my $d = shift;
  454. #
  455. # Ticks and values for X axis
  456. #
  457. my $i;
  458. for $i (0 .. $s->{numpoints}) 
  459. {
  460. my ($x, $y) = $s->val_to_pixel($i + 1, 0, 1);
  461. $y = $s->{bottom} unless $s->{zero_axis_only};
  462. next 
  463. if ( !$s->{x_all_ticks} and 
  464. $i%($s->{x_label_skip}) and $i != $s->{numpoints} );
  465. if ($s->{x_ticks})
  466. {
  467. if ($s->{long_ticks})
  468. {
  469. $g->line( 
  470. $x, $s->{bottom}, $x, 
  471. $s->{top},
  472. $s->{fgci} 
  473. );
  474. }
  475. else
  476. {
  477. $g->line( $x, $y, $x, $y - $s->{tick_length},
  478.   $s->{fgci} );
  479. }
  480. }
  481. next 
  482. if ( $i%($s->{x_label_skip}) and $i != $s->{numpoints} );
  483. if ($s->{x_labels_vertical})
  484. {
  485. $x -= $s->{xafw};
  486. my $yt = 
  487. $y + $s->{text_space}/2 + $s->{xafw} * length($d->[0][$i]);
  488. $g->stringUp($s->{xaf}, $x, $yt, $d->[0][$i], $s->{alci});
  489. }
  490. else
  491. {
  492. $x -= $s->{xafw} * length($d->[0][$i])/2;
  493. my $yt = $y + $s->{text_space}/2;
  494. $g->string($s->{xaf}, $x, $yt, $d->[0][$i], $s->{alci});
  495. }
  496. }
  497. }
  498. # CONTRIB Scott Prahl
  499. # Assume x array contains equally spaced x-values
  500. # and generate an appropriate axis
  501. #
  502. sub draw_x_ticks_number($$) # GD::Image, @data
  503. {
  504. my $s = shift;
  505. my $g = shift;
  506. my $d = shift;
  507. my $i;
  508. for $i (0 .. $s->{x_tick_number})
  509. {
  510. my $value = $s->{numpoints}
  511. * ($s->{x_values}[$i] - $s->{true_x_min})
  512.             / ($s->{true_x_max} - $s->{true_x_min});
  513. my $label = $s->{x_values}[$i];
  514. my ($x, $y) = $s->val_to_pixel($value + 1, 0, 1);
  515. $y = $s->{bottom} unless $s->{zero_axis_only};
  516. if ($s->{x_ticks})
  517. {
  518. if ($s->{long_ticks})
  519. {
  520. $g->line($x, $s->{bottom}, $x, $s->{top},$s->{fgci});
  521. }
  522. else
  523. {
  524. $g->line( $x, $y, $x, $y - $s->{tick_length}, $s->{fgci} );
  525. }
  526. }
  527. next
  528. if ( $i%($s->{x_label_skip}) and $i != $s->{x_tick_number} );
  529. if ($s->{x_labels_vertical})
  530. {
  531. $x -= $s->{xafw};
  532. my $yt =
  533. $y + $s->{text_space}/2 + $s->{xafw} * length($d->[0][$i]);
  534. $g->stringUp($s->{xaf}, $x, $yt, $label, $s->{alci});
  535. }
  536. else
  537. {
  538. # $x -= $s->{xafw} * length($$d[0][$i])/2;
  539. $x -=  length($d->[0][$i])/2;
  540. my $yt = $y + $s->{text_space}/2;
  541. $g->string($s->{xaf}, $x, $yt, $label, $s->{alci});
  542. }
  543. }
  544. }
  545. sub draw_ticks($$) # GD::Image, @data
  546. {
  547. my $s = shift;
  548. my $g = shift;
  549. my $d = shift;
  550. $s->draw_y_ticks($g, $d);
  551. return unless ( $s->{x_plot_values} );
  552. if (defined $s->{x_tick_number})
  553. {
  554. $s->draw_x_ticks_number($g, $d);
  555. }
  556. else
  557. {
  558. $s->draw_x_ticks($g, $d);
  559. }
  560. }
  561.  
  562. sub draw_data($$) # GD::Image, @data
  563. {
  564. my $s = shift;
  565. my $g = shift;
  566. my $d = shift;
  567. my $ds;
  568. foreach $ds (1 .. $s->{numsets}) 
  569. {
  570. $s->draw_data_set($g, $d->[$ds], $ds);
  571. }
  572. }
  573. # draw_data_set is in sub classes
  574. sub draw_data_set()
  575. {
  576. # ABSTRACT
  577. my $s = shift;
  578. $s->die_abstract( "sub draw_data missing, ")
  579. }
  580.  
  581. # Figure out the maximum values for the vertical exes, and calculate
  582. # a more or less sensible number for the tops.
  583. sub set_max_min($)
  584. {
  585. my $s = shift;
  586. my $d = shift;
  587. my @max_min;
  588. # First, calculate some decent values
  589. if ( $s->{two_axes} ) 
  590. {
  591. my $i;
  592. for $i (1 .. 2) 
  593. {
  594. my $true_y_min = get_min_y(@{$$d[$i]});
  595. my $true_y_max = get_max_y(@{$$d[$i]});
  596. ($s->{y_min}[$i], $s->{y_max}[$i], $s->{y_tick_number}) =
  597. _best_ends($true_y_min, $true_y_max, $s->{y_tick_number});
  598. }
  599. else 
  600. {
  601. my ($true_y_min, $true_y_max) = $s->get_max_min_y_all($d);
  602. ($s->{y_min}[1], $s->{y_max}[1], $s->{y_tick_number}) =
  603. _best_ends($true_y_min, $true_y_max, $s->{y_tick_number});
  604. }
  605. if (defined( $s->{x_tick_number} ))
  606. {
  607. $s->{true_x_min} = get_min_y(@{$d->[0]});
  608. $s->{true_x_max} = get_max_y(@{$d->[0]});
  609. ($s->{x_min}, $s->{x_max}, $s->{x_tick_number}) =
  610. _best_ends( $s->{true_x_min}, $s->{true_x_max}, 
  611. $s->{x_tick_number});
  612. }
  613. # Make sure bars and area always have a zero offset
  614. if (ref($s) eq 'GIFgraph::bars' or ref($s) eq 'GIFgraph::area')
  615. {
  616. $s->{y_min}[1] = 0 if $s->{y_min}[1] > 0;
  617. $s->{y_min}[2] = 0 if $s->{y_min}[2] && $s->{y_min}[2] > 0;
  618. }
  619. # Overwrite these with any user supplied ones
  620. $s->{y_min}[1] = $s->{y_min_value}  if defined $s->{y_min_value};
  621. $s->{y_min}[2] = $s->{y_min_value}  if defined $s->{y_min_value};
  622. $s->{y_max}[1] = $s->{y_max_value}  if defined $s->{y_max_value};
  623. $s->{y_max}[2] = $s->{y_max_value}  if defined $s->{y_max_value};
  624. $s->{y_min}[1] = $s->{y1_min_value} if defined $s->{y1_min_value};
  625. $s->{y_max}[1] = $s->{y1_max_value} if defined $s->{y1_max_value};
  626. $s->{y_min}[2] = $s->{y2_min_value} if defined $s->{y2_min_value};
  627. $s->{y_max}[2] = $s->{y2_max_value} if defined $s->{y2_max_value};
  628. $s->{x_min}    = $s->{x_min_value}  if defined $s->{x_min_value};
  629. $s->{x_max}    = $s->{x_max_value}  if defined $s->{x_max_value};
  630. # Check to see if we have sensible values
  631. if ( $s->{two_axes} ) 
  632. {
  633. my $i;
  634. for $i (1 .. 2)
  635. {
  636. die "Minimum for y" . $i . " too largen"
  637. if ( $s->{y_min}[$i] > get_min_y(@{$d->[$i]}) );
  638. die "Maximum for y" . $i . " too smalln"
  639. if ( $s->{y_max}[$i] < get_max_y(@{$d->[$i]}) );
  640. }
  641. # else 
  642. # {
  643. # die "Minimum for y too largen"
  644. # if ( $s->{y_min}[1] > $max_min[1] );
  645. # die "Maximum for y too smalln"
  646. # if ( $s->{y_max}[1] < $max_min[0] );
  647. # }
  648. }
  649.  
  650. # return maximum value from an array
  651.  
  652. sub get_max_y(@) # array
  653. {
  654. my $max = undef;
  655. my $i;
  656. foreach $i (@_) 
  657. next unless defined $i;
  658. $max = (defined($max) && $max >= $i) ? $max : $i; 
  659. }
  660. return $max
  661. }
  662. sub get_min_y(@) # array
  663. {
  664. my $min = undef;
  665. my $i;
  666. foreach $i (@_) 
  667. next unless defined $i;
  668. $min = ( defined($min) and $min <= $i) ? $min : $i;
  669. }
  670. return $min
  671. }
  672.  
  673. # get maximum y value from the whole data set
  674.  
  675. sub get_max_min_y_all($) # @data
  676. {
  677. my $s = shift;
  678. my $d = shift;
  679. my $max = undef;
  680. my $min = undef;
  681. if ($s->{overwrite} == 2) 
  682. {
  683. my $i;
  684. for $i (0 .. $s->{numpoints}) 
  685. {
  686. my $sum = 0;
  687. my $j;
  688. for $j (1 .. $s->{numsets}) 
  689. $sum += $d->[$j][$i]; 
  690. }
  691. $max = _max( $max, $sum );
  692. $min = _min( $min, $sum );
  693. }
  694. }
  695. else 
  696. {
  697. my $i;
  698. for $i ( 1 .. $s->{numsets} ) 
  699. {
  700. $max = _max( $max, get_max_y(@{$d->[$i]}) );
  701. $min = _min( $min, get_min_y(@{$d->[$i]}) );
  702. }
  703. }
  704. return ($max, $min)
  705. }
  706. # CONTRIB Scott Prahl
  707. #
  708. # Calculate best endpoints and number of intervals for an axis and
  709. # returns ($nice_min, $nice_max, $n), where $n is the number of
  710. # intervals and
  711. #
  712. #    $nice_min <= $min < $max <= $nice_max
  713. #
  714. # Usage:
  715. # ($nmin,$nmax,$nint) = _best_ends(247, 508);
  716. # ($nmin,$nmax) = _best_ends(247, 508, 5); 
  717. #  use 5 intervals
  718. # ($nmin,$nmax,$nint) = _best_ends(247, 508, 4..7);
  719. #  best of 4,5,6,7 intervals
  720. sub _best_ends {
  721. my ($min, $max, @n) = @_;
  722. my ($best_min, $best_max, $best_num) = ($min, $max, 1);
  723. # fix endpoints, fix intervals, set defaults
  724. ($min, $max) = ($max, $min) if ($min > $max);
  725. ($min, $max) = ($min) ? ($min * 0.5, $min * 1.5) : (-1,1) 
  726. if ($max == $min);
  727. @n = (3..6) if (@n <= 0 || $n[0] =~ /auto/i);
  728. my $best_fit = 1e30;
  729. my $range = $max - $min;
  730. # create array of interval sizes
  731. my $s = 1;
  732. while ($s < $range) { $s *= 10 }
  733. while ($s > $range) { $s /= 10 }
  734. my @step = map {$_ * $s} (0.2, 0.5, 1, 2, 5);
  735. for (@n) 
  736. {
  737. # Try all numbers of intervals
  738. my $n = $_;
  739. next if ($n < 1);
  740. for (@step) 
  741. {
  742. next if ($n != 1) && ($_ < $range/$n); # $step too small
  743. my $nice_min   = $_ * int($min/$_);
  744. $nice_min  -= $_ if ($nice_min > $min);
  745. my $nice_max   = ($n == 1) 
  746. ? $_ * int($max/$_ + 1) 
  747. : $nice_min + $n * $_;
  748. my $nice_range = $nice_max - $nice_min;
  749. next if ($nice_max < $max); # $nice_min too small
  750. next if ($best_fit <= $nice_range - $range); # not closer fit
  751. $best_min = $nice_min;
  752. $best_max = $nice_max;
  753. $best_fit = $nice_range - $range;
  754. $best_num = $n;
  755. }
  756. }
  757. return ($best_min, $best_max, $best_num)
  758. }
  759. # Convert value coordinates to pixel coordinates on the canvas.
  760.  
  761. sub val_to_pixel($$$) # ($x, $y, $i) in real coords ($Dataspace), 
  762. { # return [x, y] in pixel coords
  763. my $s = shift;
  764. my ($x, $y, $i) = @_;
  765. my $y_min = 
  766. ($s->{two_axes} && $i == 2) ? $s->{y_min}[2] : $s->{y_min}[1];
  767. my $y_max = 
  768. ($s->{two_axes} && $i == 2) ? $s->{y_max}[2] : $s->{y_max}[1];
  769. my $y_step = abs(($s->{bottom} - $s->{top})/($y_max - $y_min));
  770. return ( 
  771. _round( ($s->{x_tick_number} ? $s->{x_offset} : $s->{left}) 
  772. + $x * $s->{x_step} ),
  773. _round( $s->{bottom} - ($y - $y_min) * $y_step )
  774. )
  775. }
  776. } # End of package GIFgraph::axestype
  777.  
  778. 1;