[Matrix-SIG] algorithm for intelligent axis scaling?

Mike Miller miller5@uiuc.edu
19 Mar 1999 08:52:12 -0600

Note: I've CC'd this to plot-sig as well as matrix-sig.  Might be
some people there who'll be interested in this discussion.

>>>>> On matrix-sig, Alexander Lawhead <alawhead@vcn.bc.ca> writes:

    > This is not directly a NumPy question, but I figured that
    > the best answer might come from this group. :) I'm looking
    > for a simple algorithm for generating intelligent axis
    > scalings for a graph. Basically what I need is the axis
    > minimum, axis maximum, and step length between ticks given
    > the minimum data value, maximum data value, and suggested
    > number of ticks.  By intelligent, I mean reasonably
    > intuitive rounding for the axis labels!

    > This should be easy, but I'm afraid I've been spoiled by
    > automagical plotting in countless canned graphics
    > packages. Any help would be appreciated.

Here's how I do it in some DISLIN utilities.  Scales calculates
what I think are ok values for linear or log10 scales and sets up
dislin's axes with dislin.graf.  If I'm plotting xy pairs with
uncertainties dx and dy, Scales is called like this:

    Scales( min(x), max(x), min(y-dy), max(y+dy) )

On the aesthetic scale, this version leans more to serviceable
than beautiful - I'm glad to see the other methods that have been

Thanks, Mike

Michael A. Miller                                miller5@uiuc.edu
  Department of Physics, University of Illinois, Urbana-Champaign

# --- excerpts from DISLIN PlutUtils.py ---
# Default number of divisions on each axis:
Ndiv = 10

def Scales(x1, x2, y1, y2, xlog='lin', ylog='lin'):
    if xlog == 'log':
        xmin, xmax, xlowTick, xStep = log10Scale(x1,x2)
        xmin, xmax, xlowTick, xStep, xdig = linearScale(x1,x2)
        dislin.digits(xdig, 'x')

    if ylog == 'log':
        ymin, ymax, ylowTick, yStep = log10Scale(y1,y2)
        ymin, ymax, ylowTick, yStep, ydig = linearScale(y1,y2)
        dislin.digits(ydig, 'y')

    dislin.graf( xmin, xmax, xlowTick, xStep,
		 ymin, ymax, ylowTick, yStep )

def linearScale(a1,a2):
    width = float(a2) - float(a1)
    step = width/float(Ndiv)
    istep = pow(10.0,int(cmath.log10(step).real))

    Step = math.ceil(step/istep)*istep
    lowTick = math.floor(a1/Step)*Step

    if a1 == 0.0:
	amin = a1
	amin = a1 - Step/2.0
    amax = a2 + Step/2.0

    if lowTick < min:
        lowTick = lowTick + Step
    if amax-amin > 10.0:
        adig = 0
        adig = - math.floor(math.log10(amax-amin)) + 1

    return amin, amax, lowTick, Step, adig

def log10Scale(a1, a2):
    amax = math.ceil(math.log10(a2))
    if a1 <= 0.0:
        amin = amax - 3
        amin = math.floor(math.log10(a1))
    return amin, amax, amin, 1.0