## Version 0 of Nice Numbers

Updated 2006-09-01 01:27:35 by kpv

KPV I was recently searching this wiki for routines for drawing charts when I saw in two different places two similar, but very clever, routines that I thought deserved a page to themselves.

The problem they solve for graphs is determining the range for an axis that encompasses the range of values of the graph but begin and end on Nice Numbers. For example, with a range of, say, 5-86 you'd like the axis to range from 0-100.

The first algorithm is from Chart generation support by Dave Griffin.

``` #
# nice_number
#
#   Reference: Paul Heckbert, "Nice Numbers for Graph Labels",
#          Graphics Gems, pp 61-63.
#
#   Finds a "nice" number approximately equal to x.
#
#   Args: x -- target number
#         round -- If non-zero, round. Otherwise take ceiling of value.

proc nice_number {x {round 0}} {

#   expt -- Exponent of x
#   frac -- Fractional part of x
#   nice -- Nice, rounded fraction

set expt [expr {floor(log10(\$x))}]
set frac [expr {\$x / pow(10.0, double(\$expt))}]
if (\$round) {
if {\$frac < 1.5} {
set nice 1.0
} elseif {\$frac < 3.0} {
set nice 2.0
} elseif {\$frac < 7.0} {
set nice 5.0
} else {
set nice 10.0
}
} else {
if {\$frac <= 1.0} {
set nice  1.0
} elseif {\$frac <= 2.0} {
set nice  2.0
} elseif {\$frac <= 5.0} {
set nice 5.0
} else {
set nice 10.0
}
}
return [expr {\$nice * pow(10.0, double(\$expt))}]
}

```

The second routine is from A little bar chart by the ubiquitous Richard Suchenwirth.

``` # An interesting sub-challenge was to round numbers very roughly,
# to 1 or maximally 2 significant digits - by default rounding up,
# add "-" to round down:}
proc Roughly {n {sgn +}} {
regexp {(.+)e([+-])0*(.+)} [format %e \$n] -> mant sign exp
set exp [expr \$sign\$exp]
if {abs(\$mant)<1.5} {
set mant [expr {\$mant*10}]
incr exp -1
}
set t [expr round(\$mant \$sgn 0.49)*pow(10,\$exp)]
expr {\$exp>=0? int(\$t): \$t}
}```