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} }
tklib plotchart has a similar routine that also computes a good tick interval.
package require plotchart foreach {niceMin niceMax niceTicks} [::plotchart::determineScale $min $max] break
# Test: catch {console show} catch {wm withdraw .} foreach x {7 11 22 33 44 77} { puts "$x nice_number: [nice_number $x]" puts "$x Roughly : [Roughly $x] \n" }
HJG Test added.