データをGIFファイルに
"temp_chart.pl"
1 #!/usr/local/bin/perl
2
3 # "temp_chart.pl"
4
5 # The following is a Perl version of the charting function.
6 # The Perl OR operator | can be used to combine
7 # any or all of these.
8
9 $chartBar = 1;
10 $chartCross = 2;
11 $chartLine = 4;
12
13 # A function to draw a chart on the specified gd image. The
14 # chart will occupy the entire image. The image should
15 # be created first with gdImageCreate(). The "units"
16 # string must be no longer than 100 characters!
17 #
18 # chartDraw should be invoked with a GD.pm image object,
19 # the chart type (see above), an array of X axis labels
20 # (which can be empty), the unit of measurement
21 # for the Y axis, and an array of numeric data values.
22
23 use GD;
24
25 sub chartDraw
26 {
27 local($im, $t, *labels, $units, *data, *glabels, *gdata) = @_;
28
29 $points = @data;
30 $gpoints = @gdata;
31
32 # First, allocate colors.
33 $backgroundColor = $im->colorAllocate(192, 192, 192);
34
35 # Set this as the transparent color for the GIF.
36 $im->transparent($backgroundColor);
37
38 $borderColor = $im->colorAllocate(0, 0, 0);
39
40 $textColor = $im->colorAllocate(0, 0, 0);
41
42 $tickColor = $im->colorAllocate(64, 64, 64);
43
44 if (! $points) {
45 # Nothing to draw!
46 return;
47 }
48
49 $barColor = $im->colorAllocate(130,130 , 255);
50 $bar2Color = $im->colorAllocate(180,180,255);
51 $lineColor = $im->colorAllocate(255, 64, 64);
52 $crossColor = $im->colorAllocate(0, 120, 0);
53
54
55 # Second, find the range of the data.
56 $dataMin = 15;
57 $dataMax = 35;
58 $dataRange = $dataMax - $dataMin;
59 $labelsMin = 0;
60 $labelsMax = 24;
60 $labelsMax = 24;
61 $labelsRange = $labelsMax - $labelsMin;
62
63
64 # Decide how much space is available. Start with all of it...
65
66 @imSize = $im->getBounds();
67 $spaceX = $imSize[0];
68
69 # The left edge is occupied by the Y axis labels and numbers,
70 # plus a bit of space for aesthetic purposes...
71 $baseX = 0;
72 if ($units ne "") {
73 $baseX += gdLargeFont->height;
74 }
75
76 $baseX += gdLargeFont->height + 2 +3;
77
78 # Subtract that space from the space available for the graph...
79 $spaceX -= $baseX + 10;
80
81 # Now compute the space available on the Y axis.
82 $spaceY = $imSize[1];
83
84 $spaceY -= (gdLargeFont->height + 2 + 18);
85
86 $baseY = 0;
87
88 # Make sure we don't divide by zero.
89 if (!$dataRange) {
90 $dataRange = 1.0;
91 }
92
93 if (!$dataRange) {
94 $dataRange = 1.0;
95 }
96
97 # Discover how many Y-axis "ticks" are appropriate.
98 # There should be at least two and no more than twenty, and
99 # the step between ticks should be a power of ten.
100 $tick = 5.0 ** int(log($dataRange / 2.0) / log(10.0));
101 $tickAccum = $tick * (int($dataMin / $tick) + 1);
102
103 # Decide the divisor for labels.
104 # Powers of 1000 are familiar
105 # to the user.
106 $divisor = 1.0;
107 if (abs($dataMax) > abs($dataMin)) {
108 while (abs($dataMax) / $divisor >= 1000.0) {
109 $divisor *= 1000.0;
110 }
111 } else {
112 while (abs($dataMin) / $divisor >= 1000.0) {
113 $divisor *= 1000.0;
114 }
115 }
116 # Draw the tick lines now, so they will appear
117 # "behind" the graph. Also label the ticks
118 # as often as is possible without crowding.
119
120 for ($i = 1; $i < 24; $i++){
121 $im->line($baseX + $i*$spaceX/24.0, $baseY, $baseX + $i*$spaceX/24.0, $baseY + $spaceY, $bar2Color);
122 }
123
124 for ($i = 1; $i < 20; $i++){
125 $im->line($baseX, $i*$spaceY/20.0, $baseX + $spaceX, $i*$spaceY/20.0, $bar2Color);
126 }
127
128 $first = 1;
129 while ($tickAccum <= $dataMax) {
130 $y = $spaceY - ($spaceY * ($tickAccum - $dataMin) / $dataRange)
131 + $baseY;
132 # Format the tick label, and see if there is enough
133 # space after the previous one to make room for
134 # a text label.
135 $s = sprintf("%3.0f", $tickAccum / $divisor);
136 $w = gdLargeFont->width * length($s);
137 $textY = $y + $w / 2;
138 if ($first || ($textY < $lastLabel)) {
139 # Don't actually draw it unless it fits
140 # in the image
141 if (($textY - $w > $baseY) &&
142 ($textY < ($spaceY + $baseY))) {
143 $im->stringUp(gdLargeFont,
144 $baseX - gdLargeFont->height,
145 $textY, $s, $textColor);
146 }
147 # The extra two pixels are for aesthetic purposes
148 $lastLabel = $y - $w / 2 - 2;
149 $first = 0;
150 }
151
152 $im->line($baseX, $y, $baseX + $spaceX, $y, $barColor);
153 $tickAccum += $tick;
154 }
155
156 # Now draw the graph.
157 for ($i=0; ($i < $gpoints); $i++) {
158 local($gx, $gy, $gw) = (0, 0, 0);
159 $gx = $spaceX * ($glabels[$i] - $labelsMin) / $labelsRange + $baseX;
160 $gy = $spaceY - ($spaceY * ($gdata[$i] - $dataMin) / $dataRange)
161 + $baseY;
162
163 $im->line($gx - 2, $gy - 2, $gx + 2, $gy + 2, $crossColor);
164 $im->line($gx + 2, $gy - 2, $gx - 2, $gy + 2, $crossColor);
165 $lastX = $gx;
166 $lastY = $gy;
167 }
168 for ($i=0; ($i < $points); $i++) {
169 local($x, $y, $w) = (0, 0, 0);
170 $x = $spaceX * ($labels[$i] - $labelsMin) / $labelsRange + $baseX;
171 $y = $spaceY - ($spaceY * ($data[$i] - $dataMin) / $dataRange)
172 + $baseY;
173
174
175
176 if ($t & $chartLine) {
177 if ($i) {
178 $im->line($lastX, $lastY, $x, $y, $lineColor);
179 }
180 }
181 $lastX = $x;
182 $lastY = $y;
183 }
184
185 # Draw the border lines at left and bottom...
186 $im->line($baseX, $baseY, $baseX, $baseY + $spaceY, $barColor);
187 $im->line($baseX, $baseY + $spaceY,
188 $baseX + $spaceX, $baseY + $spaceY, $barColor);
189
190 # Draw the border line at right..
191 $im->line($baseX + $spaceX -1, $baseY + $spaceY,$baseX + $spaceX -1, $baseY, $barColor);
192 for ($i = 1; $i < 8; $i++){
193 $im->line($baseX + $i*$spaceX/8.0, $baseY, $baseX + $i*$spaceX/8.0, $baseY + $spaceY, $barC
194 }
195 for ($i = 0; $i < 9; $i++){
196 $im->string(gdLargeFont,$baseX + $i*$spaceX/8.0-6,$baseY +$spaceY + 2,$i*3, $textColor);
197 }
198 $im->string(gdLargeFont,$baseX + 150,$baseY +$spaceY + 20,"Time (hour)", $textColor);
199
200 # Label the Y axis (units)
201 if ($units ne "") {
202 local($h, $label) = ( 0 , "" );
203 if ($divisor != 1.0) {
204 $label = sprintf("%s x %2.0f", $units, $divisor);
205 } else {
206 $label = $units;
207 }
208 # Rotated 90 degrees
209 $h = gdLargeFont->width * length($label);
210 $im->stringUp(gdLargeFont,
211 0, $baseY + ($spaceY / 2) + ($h / 2),
212 $label, $textColor);
213 } else {
214 local($h, $label) = ( 0 , "" );
215 if ($divisor != 1.0) {
216 $label = sprintf("x%2.0f", $divisor);
217 } else {
218 $label = "";
219 }
220 # Rotated 90 degrees
221 $h = gdLargeFont->width * length(label);
222 $im->stringUp(gdLargeFont,
223 0, $baseY + ($spaceY / 2) + ($h / 2),
224 $label, $textColor);
225 }
226 }
SST_Labo's Home Page