PLplot: pldtik.c Source File

PLplot 5.15.0

pldtik.c
Go to the documentation of this file.
1 // Determine tick spacing and mode (fixed or floating) of
2 // numeric axis labels.
3 //
4 // Copyright (C) 2004-2014 Alan W. Irwin
5 //
6 // This file is part of PLplot.
7 //
8 // PLplot is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU Library General Public License as published
10 // by the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // PLplot is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Library General Public License for more details.
17 //
18 // You should have received a copy of the GNU Library General Public License
19 // along with PLplot; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 //
22
23 #include "plplotP.h"
24
25 //--------------------------------------------------------------------------
26 // void pldtik()
27 //
28 // Determine tick spacing: works out a "nice" interval (if tick == 0) such
29 // that there are between 3 and 7.5 major tick intervals in the input
30 // range vmin to vmax. The recommended number of subticks is returned in
31 // "nsubt" unless the routine is entered with a non-zero value of "nsubt".
32 // n.b. big change: now returns only positive values of tick and nsubt
33 //--------------------------------------------------------------------------
34
35 void
36 pldtik( PLFLT vmin, PLFLT vmax, PLFLT *tick, PLINT *nsubt, PLBOOL ld )
37 {
38 PLFLT t1, t2, tick_reasonable;
39 PLINT np, ns;
40 // Unnecessarily set factor to quiet -O3 -Wuninitialized warnings.
41 PLFLT factor = 0.0;
42
43
44 if ( ld )
45 {
46 // Check suitable units for tick spacing
47 pldtfac( vmin, vmax, &factor, NULL );
48
49 *tick = *tick / factor;
50 vmin = vmin / factor;
51 vmax = vmax / factor;
52 }
53
54 // Magnitude of min/max difference to get tick spacing
55
56 t1 = (PLFLT) log10( ABS( vmax - vmin ) );
57 np = (PLINT) floor( t1 );
58 t1 = t1 - np;
59
60 // Get tick spacing.
61
62 if ( t1 > 0.7781512503 )
63 {
64 t2 = 2.0;
65 ns = 4;
66 }
67 else if ( t1 > 0.4771212549 )
68 {
69 t2 = 1.0;
70 ns = 5;
71 }
72 else if ( t1 > 0.1760912591 )
73 {
74 t2 = 5.0;
75 ns = 5;
76 np = np - 1;
77 }
78 else
79 {
80 t2 = 2.0;
81 ns = 4;
82 np = np - 1;
83 }
84
85 // Now compute reasonable tick spacing
86
87 tick_reasonable = t2 * pow( 10.0, (double) np );
88 if ( *tick == 0 )
89 {
90 *tick = t2 * pow( 10.0, (double) np );
91 }
92 else
93 {
94 *tick = ABS( *tick );
95 if ( *tick < 1.e-4 * tick_reasonable )
96 {
97 plexit( "pldtik: magnitude of specified tick spacing is much too small" );
98 return;
99 }
100 }
101 if ( *nsubt == 0 )
102 *nsubt = ns;
103
104 *nsubt = ABS( *nsubt );
105
106 if ( ld )
107 {
108 *tick = *tick * factor;
109 }
110 }
111
112 //--------------------------------------------------------------------------
113 // PLFLT pldtfac()
114 //
115 // Calculate factor to convert a date/time interval in seconds
116 // into a more natural units (minutes, hours, days, week, years).
117 // Also optionally calculate the sensible start time for counting ticks
118 // from (e.g. beginning of day, beginning of year).
119 // Used to calculate sensible tick and label spacings.
120 //--------------------------------------------------------------------------
121 void
122 pldtfac( PLFLT vmin, PLFLT vmax, PLFLT *factor, PLFLT *start )
123 {
124 PLFLT diff;
125 PLINT year, month, day, hour, min;
126 PLFLT sec;
127
128 diff = vmax - vmin;
129
130 if ( start != NULL )
131 {
132 plbtime( &year, &month, &day, &hour, &min, &sec, vmin );
133 }
134
135 if ( diff < 3.0 * 60.0 )
136 {
137 // Seconds
138 *factor = 1.0;
139 if ( start != NULL )
140 {
141 sec = 0.;
142 plctime( year, month, day, hour, min, sec, start );
143 }
144 }
145 else if ( diff < 3.0 * 60.0 * 60.0 )
146 {
147 // Minutes
148 *factor = 60.0;
149 if ( start != NULL )
150 {
151 sec = 0.;
152 min = 0;
153 plctime( year, month, day, hour, min, sec, start );
154 }
155 }
156 else if ( diff < 3.0 * 60.0 * 60.0 * 24.0 )
157 {
158 // Hours
159 *factor = 60.0 * 60.0;
160 if ( start != NULL )
161 {
162 sec = 0.;
163 min = 0;
164 hour = 0;
165 plctime( year, month, day, hour, min, sec, start );
166 }
167 }
168 else if ( diff < 3.0 * 60.0 * 60.0 * 24.0 * 7.0 )
169 {
170 // Days
171 *factor = 60.0 * 60.0 * 24.0;
172 if ( start != NULL )
173 {
174 sec = 0.;
175 min = 0;
176 hour = 0;
177 plctime( year, month, day, hour, min, sec, start );
178 }
179 }
180 else if ( diff < 3.0 * 60.0 * 60.0 * 24.0 * 365 )
181 {
182 // Weeks
183 *factor = 60.0 * 60.0 * 24.0 * 7.0;
184 if ( start != NULL )
185 {
186 sec = 0.;
187 min = 0;
188 hour = 0;
189 plctime( year, month, day, hour, min, sec, start );
190 }
191 }
192 else
193 {
194 // Years
195 *factor = 60.0 * 60.0 * 24.0 * 365.25;
196 if ( start != NULL )
197 {
198 sec = 0.;
199 min = 0;
200 hour = 0;
201 day = 0;
202 month = 0;
203 plctime( year, month, day, hour, min, sec, start );
204 }
205 }
206 }
207
208 //--------------------------------------------------------------------------
209 // void pldprec()
210 //
211 // Determine precision: the output variable "mode" is set to 0 if labels
212 // are to be written in floating-point format, or to 1 if they are to be
213 // written in scientific format. For mode = 1, the exponent will be
214 // placed at:
215 //
216 // top left for vertical axis on left
217 // top right for vertical axis on right
218 // bottom right for horizontal axis
219 //
220 // The digmax flag can be set by the user, and represents the maximum
221 // number of digits a label may occupy including sign and decimal point.
222 // digmin, calculated internally, is the maximum number of digits
223 // labels at vmin and vmax would occupy if floating point.
224 // If digmax<0, it is disregarded,
225 // and if digmax=0 the default value is used. For digmax>0, mode=1 is
226 // chosen if there is insufficient room for the label within the specified
227 // # of digits (digmin > digfix, where digfix is determined from digmax with
228 // fuzz factors).
229 //
230 // In the case of mode=0, the actual # of digits will become too large
231 // when the magnitude of the labels become too large. The mode=1 case
232 // offers the greatest precision for the smallest field length.
233 //
234 // The determination of maximum length for fixed point quantities is
235 // complicated by the fact that very long fixed point representations look
236 // much worse than the same sized floating point representation. Further,
237 // a fixed point number with a large negative exponent will actually gain
238 // in precision when written as floating point. Thus we use certain fuzz
239 // factors to get 'digfix' from 'digmax', however it will always be true
240 // that digfix<=digmax.
241 //
242 // Finally, if 'digmax' is set, 'prec' is reduced in size if necessary so
243 // that the labels fit the requested field length, where prec is the number of
244 // places after the decimal place.
245 //--------------------------------------------------------------------------
246
247 #define MIN_FLTDIG 3 // disregarded if fractional part is 0
248 #define DIGMAX_DEF 5
249
250 void
251 pldprec( PLFLT vmin, PLFLT vmax, PLFLT tick, PLINT lf,
252 PLINT *mode, PLINT *prec, PLINT digmax, PLINT *scale )
253 {
254 PLFLT chosen, notchosen, vmod, t0;
255 PLINT msd, notmsd, np, digmin, digfix;
256
257 *mode = 0;
258 *scale = 0;
259
260 // Default xdigmax, ydigmax and zdigmax set in c_plinit so this is
261 // only an emergency measure in case of some internal PLplot
262 // logic error.
263 if ( digmax == 0 )
264 digmax = DIGMAX_DEF;
265 // No modification of digfix from digmax value.
266 digfix = digmax;
267 // Choose vmin or vmax depending on magnitudes of vmin and vmax.
268 chosen = ( ABS( vmax ) >= ABS( vmin ) ) ? vmax : vmin;
269 notchosen = ( ABS( vmax ) >= ABS( vmin ) ) ? vmin : vmax;
270 // Magnitute of chosen to get number of significant digits
271
272 if ( ABS( chosen ) > 0. )
273 {
274 vmod = ABS( chosen );
275 t0 = (PLFLT) log10( vmod );
276 msd = (PLINT) floor( t0 );
277 }
278 else
279 {
280 // this branch occurs only when 0. --- 0. range put in
281 vmod = 1.;
282 t0 = (PLFLT) log10( vmod );
283 msd = (PLINT) floor( t0 );
284 }
285
286 if ( ABS( notchosen ) > 0. )
287 notmsd = (PLINT) floor( (PLFLT) log10( ABS( notchosen ) ) );
288 else
289 notmsd = msd;
290 // Autoselect the mode flag
291 // 'digmin' is the minimum number of places taken up by the label
292
293 if ( msd >= 0 )
294 {
295 // n.b. no decimal point in the minimal case
296 digmin = msd + 1;
297 }
298 else
299 {
300 // adjust digmin to account for leading 0 and decimal point
301 digmin = -msd + 2;
302 }
303 // adjust digmin to account for sign on the chosen end of axis or sign on the
304 // nonchosen end of axis if notmsd = msd or (msd <= 0 and notmsd < 0)
305 // For the latter case the notchosen label starts with "-0."
306 // For checking for the latter case, the notmsd < 0 condition is redundant
307 // since notmsd <= msd always and the equal part is selected by the first
308 // condition.
309 //
310 if ( chosen < 0. || ( notchosen < 0. && ( notmsd == msd || msd <= 0 ) ) )
311 digmin = digmin + 1;
312
313 if ( digmin > digfix && !lf )
314 {
315 *mode = 1;
316 *scale = msd;
317 }
318
319 // Establish precision.
320 // It must be fine enough to resolve the tick spacing
321
322 np = (PLINT) floor( log10( ABS( tick ) ) );
323
324 if ( *mode != 0 )
325 *prec = msd - np;
326 else
327 *prec = MAX( -np, 0 );
328
329 // One last hack required: if exponent < 0, i.e. number has leading '0.',
330 // it's better to change to floating point form if the number of digits
331 // is insufficient to represent the tick spacing.
332 //
333 if ( *mode == 0 && digmax > 0 && !lf )
334 {
335 if ( t0 < 0.0 )
336 {
337 if ( digmax - 2 - *prec < 0 )
338 {
339 *mode = 1;
340 *scale = msd;
341 }
342 }
343 else
344 *prec = MAX( MIN( *prec, digmax - msd - 1 ), 0 );
345 }
346 if ( *mode != 0 )
347 {
348 *prec = msd - np;
349 *prec = MAX( MIN( *prec, MAX( digmax - 1, MIN_FLTDIG ) ), 0 );
350 }
351 }
plplotP.h
plexit
void plexit(PLCHAR_VECTOR errormsg)
Definition: plctrl.c:1958
min
int min(int a, int b)
Definition: plplot_octaveOCTAVE_wrap.cxx:2496
MIN_FLTDIG
#define MIN_FLTDIG
Definition: pldtik.c:247
plbtime
#define plbtime
Definition: plplot.h:699
MAX
#define MAX(a, b)
Definition: dsplint.c:28
plctime
#define plctime
Definition: plplot.h:708
pldtik
void pldtik(PLFLT vmin, PLFLT vmax, PLFLT *tick, PLINT *nsubt, PLBOOL ld)
Definition: pldtik.c:36
PLINT
int PLINT
Definition: plplot.h:181
MIN
#define MIN(a, b)
Definition: dsplint.c:29
PLBOOL
PLINT PLBOOL
Definition: plplot.h:204
pldtfac
void pldtfac(PLFLT vmin, PLFLT vmax, PLFLT *factor, PLFLT *start)
Definition: pldtik.c:122
DIGMAX_DEF
#define DIGMAX_DEF
Definition: pldtik.c:248
PLFLT
float PLFLT
Definition: plplot.h:163
ABS
#define ABS(a)
Definition: plplotP.h:199
pldprec
void pldprec(PLFLT vmin, PLFLT vmax, PLFLT tick, PLINT lf, PLINT *mode, PLINT *prec, PLINT digmax, PLINT *scale)
Definition: pldtik.c:251