[reportlab-users] findMinMaxStep()

Felipe Almeida Lessa felipe.lessa at gmail.com
Fri Jan 27 13:54:03 EST 2006


Hi!

Disappointed about ReportLab's way of finding how to scale the axis, I
wrote a nice function to find it out to me while keeping in mind the
appearance when ReportLab plots the graph. It can be use for any
ValueAxis on any chart, for example:

    chart = LinePlot()
    chart.data = data = [[(10, 14), (11, 23), (12, 38)], [(9, 8), (11, 9), (13, 7)]]
    chart.height = height = 10*cm
    chart.width = width = 10*cm
    for (axis, values, size, pos) in ((chart.xValueAxis, height, 0),
                                      (chart.yValueAxis, width,  1)):
        axis.valueMin, axis.valueMax, axis.valueStep = \
                       findMinMaxStep(data, size, pos=pos)

I hope someone find it useful. Here's the code:

    from types import ListType, TupleType

    def findMinMaxStep(rawData, size=5*cm, minValue=None, maxValue=None,
                       stepValue=None, aprox=50, pos=None):
        """findMinMaxStep(data, [size, ...]) -> (min, max, step)

        Find minimum, maximum and step values between steps of aprox.
        """
        # Some vars used below
        scale = 100.0/aprox
        error = aprox/2.0

        # Get only the parts of the data that we want
        data = rawData
        if type(rawData[0]) in (ListType, TupleType):
            # Flatten (remove nested)
            data = sum(rawData, [])
        if pos is not None:
            # Remove 2nd dimension
            data = [a[pos] for a in data]
        # Remove Nones
        data = [i for i in data if i is not None]

        # Get the min and max values of the data
        minData = min(data)
        maxData = max(data)
         
        if minValue is None:
            # Calculate the Min value while keeping in mind the aproximation
            Min = round((minData - error) * scale, -2) / scale
            Min = min((Min, minData)) # Prevent buggy calculations
        else:
            Min = minValue
            
        if maxValue is None:
            # Calculate the Max value while keeping in mind the aproximation
            Max = round((maxData + error) * scale, -2) / scale
            Max = max((Max, maxData)) # Prevent buggy calculations
        else:
            Max = maxValue
            
        if stepValue is None:
            # Calculate the Step value while keeping in mind the height and the
            # Min and Max values (to be coherent with what is being displayed)
            Step = round(((Max - Min) * scale * cm) / (size * 2.0), -2) / scale
        else:
            Step = stepValue
          
        # Check if the step value is valid (rounding can do disgusting things)
        if Step <= 0:
            if aprox > 15:
                if   size > 6*cm:
                    newAprox = 5
                elif size > 3.5*cm:
                    newAprox = 10
                else:
                    newAprox = 15
                return findMinMaxStep(data, size, minValue, maxValue, stepValue,
                                      newAprox)
            else:
                Step = aprox
        
        # Try to make it look good on ReportLab's algorhythm
        if minValue is None and int((Min - (1e-8*Step)) / 100) * 100 + Step != Min:
            Min -= Step
            if Min < 0 and minData >= 0:
                Min = 0

        # (Max-Min)/Step should be an integer
        if divmod(Max - Min, Step)[1] != 0:
            newMax = Min + Step * int((Max - Min) / Step)
            while newMax < Max:
                newMax += Step
            Max = newMax
            
        # Return the values we magically found
        return Min, Max, Step


-- 
"Quem excele em empregar a força militar subjulga os exércitos dos
outros povos sem travar batalha, toma cidades fortificadas dos outros
povos sem as atacar e destrói os estados dos outros povos sem lutas
prolongadas. Deve lutar sob o Céu com o propósito primordial da
'preservação'. Desse modo suas armas não se embotarão, e os ganhos
poderão ser preservados. Essa é a estratégia para planejar ofensivas."

  -- Sun Tzu, em "A arte da guerra"
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://two.pairlist.net/pipermail/reportlab-users/attachments/20060127/81e3ad74/attachment.html


More information about the reportlab-users mailing list