Gauges and Meters - Logarithmic Rotary Gauge.

Gauges and Meters - Logarithmic Rotary Gauge.
Hello,

A few posts back, I included source code to some gauges I had whipped together. After some constructive advice from John Hunter (Thanks!), I’ve had time to polish them a bit and include the logarithmic ones as promised.

···

===============================================================================

#!/usr/bin/env python

‘’’

The Log_Gauge widget draws a semi-circular gauge. You supply limits,

shaded regions, names and the current value, and invoke it like this:

from pylab import figure, show

raw_value = -4.0

limits = [ left, right ]

zone_colour = [[-1.0,0.0,'r'],[0.0,0.5,'y'],[0.5,1.0,'g']]

attribute_name = "Rx MOS (24h)"



graph_height = 1.6

graph_width  = 2.4

fig_height   = graph_height

fig_width    = graph_width

fig = figure(figsize=(fig_width, fig_height ))



rect = [(0.0/fig_width), (0.2/fig_height),

        (graph_width/fig_width), (graph_height/fig_height)]



gauge = Gauge(fig, rect,

           xlim=( -0.1, graph_width+0.1 ),

           ylim=( -0.4, graph_height+0.1 ),

           xticks=[],

           yticks=[],

           )

gauge.set_axis_off()

fig.add_axes(gauge)

show()



NOTE: The limits you specify must be of this form

    for any value of 'n':   1.0*10^n

‘’’

from future import division

from matplotlib.figure import Figure

from matplotlib.axes import Axes

import math

import types

from math import pi

class Log_Gauge(Axes):

def __init__(self, raw_value, raw_limits, raw_zones, attribute_name, field_names, file_name, resolution, x_length, y_length, *args, **kwargs):

    Axes.__init__(self, *args, **kwargs)

   

    #Perform Checking

    if( raw_limits[0] == raw_limits[1] ):

        raise ValueError('identical_limits_exception: %s' % raw_limits)

    if( raw_limits[1] > raw_limits[0] ):

        self.graph_positive = True

    else:   #Swap the limits around

        self.graph_positive = False

        raw_limits[0], raw_limits[1] = raw_limits[1] = raw_limits[0]

       

    if not( math.log10(raw_limits[0]) % 1.0 == 0 and math.log10(raw_limits[1]) % 1.0 == 0 ):

        raise ValueError('bad_limits_exception:%s' % raw_limits)

           

    for zone in raw_zones:

        if( zone[0] > zone[1] ):    #Swap the zones so zone[1] > zone[0]

            zone[0], zone[1] = zone[1], zone[0]

        if( zone[1] < raw_limits[0] or zone[0] > raw_limits[1] ):

            raise ValueError('bad_zone_exception' % zone)

        if( zone[0] < raw_limits[0] ):

            zone[0] = raw_limits[0]

        if( zone[1] > raw_limits[1] ):

            zone[1] = raw_limits[1]

                           

    #Stuff all of the variables into self.

    self.raw_value = raw_value

    self.raw_limits = raw_limits

    self.raw_zones = raw_zones

    self.attribute_name = attribute_name

    self.field_names = field_names

    self.file_name = file_name

    self.resolution = resolution

    self.x_length = x_length

    self.y_length = y_length

   

   

    #Draw the arch

    for zone in raw_zones:

        self.draw_arch( zone, False )

    self.draw_arch( None, True )

    self.draw_ticks()

    self.draw_needle()

    self.draw_bounding_box()

    self.text(0.0, 0.3, attribute_name, size=10, va='center', ha='center')

   

    #The black dot

    p = self.plot([0.0],[0.0],'.', color='#000000')           



def draw_arch( self, zone, border ):

    if( border ):

        start  = self.raw_limits[0]

        end    = self.raw_limits[1]

    else:

        start  = zone[0]

        end    = zone[1]

        colour = zone[2]

   

    x_vect = []

    y_vect = []

    if( self.graph_positive ):

        start_value = int(180 - (start - self.raw_limits[0]) * (180.0/(self.raw_limits[1]-self.raw_limits[0])))

        end_value   = int(180 - (end   - self.raw_limits[0]) * (180.0/(self.raw_limits[1]-self.raw_limits[0])))

    else:

        start_value = int(      (end   - self.raw_limits[0]) * (180.0/(self.raw_limits[1]-self.raw_limits[0])))

        end_value   = int(      (start - self.raw_limits[0]) * (180.0/(self.raw_limits[1]-self.raw_limits[0])))

   

           

    if( self.graph_positive ):

        start_value = (math.log10(start) - math.log10(self.raw_limits[1])) * 180.00 / -(math.log10(self.raw_limits[1]) - math.log10(self.raw_limits[0]))

        end_value   = (math.log10(end)   - math.log10(self.raw_limits[1])) * 180.00 / -(math.log10(self.raw_limits[1]) - math.log10(self.raw_limits[0]))

    else:

        start_value = (math.log10(end)   - math.log10(self.raw_limits[0])) * 180.00 / +(math.log10(self.raw_limits[1]) - math.log10(self.raw_limits[0]))

        end_value   = (math.log10(start) - math.log10(self.raw_limits[0])) * 180.00 / +(math.log10(self.raw_limits[1]) - math.log10(self.raw_limits[0]))

   

    #Draw the arch

    theta = start_value

    radius = 0.85

    while (theta >= end_value):

        x_vect.append( radius * math.cos(theta * (pi/180)) )

        y_vect.append( radius * math.sin(theta * (pi/180)) )

        theta -= 1

           

    theta = end_value

    radius = 1.0

    while (theta <= start_value):

        x_vect.append( radius * math.cos(theta * (pi/180)) )

        y_vect.append( radius * math.sin(theta * (pi/180)) )

        theta += 1

   

    if( border ):

        #Close the loop

        x_vect.append(-0.85)

        y_vect.append(0.0)

       

        p = self.plot(x_vect, y_vect, 'b-', color='black', linewidth=1.0)

    else:

        p = self.fill(x_vect, y_vect, colour, linewidth=0.0, alpha=0.4)

       



def draw_needle( self ):

    x_vect = []

    y_vect = []

   

    if self.raw_value == None:

        self.text(0.0, 0.4, "N/A", size=10, va='bottom', ha='center')

    else:

        self.text(0.0, 0.4, "%.2f" % self.raw_value, size=10, va='bottom', ha='center')

       

        #Clamp the value to the limits

        if( self.raw_value < self.raw_limits[0] ):

            self.raw_value = self.raw_limits[0]

        if( self.raw_value > self.raw_limits[1] ):

            self.raw_value = self.raw_limits[1]

       

        theta = 0

        length = 0.95

        if( self.graph_positive ):

            angle = (math.log10(self.raw_value) - math.log10(self.raw_limits[1])) * 180.00 / -(math.log10(self.raw_limits[1]) - math.log10(self.raw_limits[0]))

        else:

            angle = (math.log10(self.raw_value) - math.log10(self.raw_limits[0])) * 180.00 / +(math.log10(self.raw_limits[1]) - math.log10(self.raw_limits[0]))



        while (theta <= 270):

            x_vect.append( length * math.cos((theta + angle) * (pi/180)) )

            y_vect.append( length * math.sin((theta + angle) * (pi/180)) )

            length = 0.05

            theta += 90

        p = self.fill(x_vect, y_vect, 'b', alpha=0.4)

           

       

       

def draw_ticks( self ):

    if( self.graph_positive ):

        angle = 180.0

    else:

        angle = 0.0

   

    i = self.raw_limits[0]

    step = self.raw_limits[0]

    x_vect = []

    y_vect = []

    while( i < self.raw_limits[1] ):

        while( i < (step * 10) ):

            x_vect = []

            y_vect = []

            value = math.log10(i)

            if( self.graph_positive ):

                angle = (value - math.log10(self.raw_limits[1])) * 180.00 / -(math.log10(self.raw_limits[1]) - math.log10(self.raw_limits[0]))

            else:

                angle = (value - math.log10(self.raw_limits[0])) * 180.00 / +(math.log10(self.raw_limits[1]) - math.log10(self.raw_limits[0]))

            x_pos = 1.1 * math.cos( angle * (pi/180.0))

            y_pos = 1.1 * math.sin( angle * (pi/180.0))

            mantissa = int(i / math.pow(10, math.ceil(math.log10(i))-1))

            if( mantissa == 10 or mantissa == 1 ):

                if( type(self.raw_limits[2]) is types.FloatType ):

                    self.text( x_pos, y_pos, "%.2f" % j, size=10, va='center', ha='center', rotation=(angle - 90))

                else:

                    self.text( x_pos, y_pos, "%d" % int(j), size=10, va='center', ha='center', rotation=(angle - 90))

                tick_length = 0.15

            else:

                tick_length = 0.05

            x_vect.append( 1.0 * math.cos( angle * (pi/180.0)))

            x_vect.append( (1.0 - tick_length) * math.cos( angle * (pi/180.0)))

            y_vect.append( 1.0 * math.sin( angle * (pi/180.0)))

            y_vect.append( (1.0 - tick_length) * math.sin( angle * (pi/180.0)))

            p = self.plot(x_vect, y_vect, 'b-', linewidth=1, alpha=0.4, color="black")

           

            i += step

        i = step * 10

        step = step * 10

    i = self.raw_limits[1]

    value = math.log10(i)

    if( self.graph_positive ):

        angle = (value - math.log10(self.raw_limits[1])) * 180.00 / -(math.log10(self.raw_limits[1]) - math.log10(self.raw_limits[0]))

    else:

        angle = (value - math.log10(self.raw_limits[0])) * 180.00 / +(math.log10(self.raw_limits[1]) - math.log10(self.raw_limits[0]))

    x_pos = 1.1 * math.cos( angle * (pi/180.0))

    y_pos = 1.1 * math.sin( angle * (pi/180.0))

    mantissa = int(i / math.pow(10, math.ceil(math.log10(i))-1))

    if( mantissa == 10 ):

        if( type(self.raw_limits[2]) is types.FloatType ):

            self.text( x_pos, y_pos, "%.2f" % j, size=10, va='center', ha='center', rotation=(angle - 90))

        else:

            self.text( x_pos, y_pos, "%d" % int(j), size=10, va='center', ha='center', rotation=(angle - 90))   

   

   

   

def draw_bounding_box( self ):

    x_vect = [

        self.x_length/2,

        self.x_length/2,

        -self.x_length/2,

        -self.x_length/2,

        self.x_length/2,

        ]

    y_vect = [

        -0.1,

        self.y_length,

        self.y_length,

        -0.1,

        -0.1,

        ]

    p = self.plot(x_vect, y_vect, 'r-', linewidth=0)

def make_widget( raw_value, raw_limits, raw_zones, attribute_name, field_names, file_name, resolution=72 ):

from pylab import figure, show, savefig

x_length = 2.4  # Length of the Primary axis

y_length = 1.6  # Length of the Secondary axis

   

fig_height = y_length

fig_width  = x_length

fig = figure( figsize=(fig_width, fig_height) )

rect = [(0.0/fig_width), (0.2/fig_height), (x_length/fig_width), (y_length/fig_height)]

gauge = Log_Gauge( raw_value,

    raw_limits, raw_zones,

    attribute_name, field_names,

    file_name, resolution,

    x_length, y_length,

    fig, rect,

    xlim=( -0.1, x_length+0.1 ),

    ylim=( -0.4, y_length+0.1 ),

    xticks=[],

    yticks=[],

    )

       

gauge.set_axis_off()

fig.add_axes(gauge)

show()

fig.canvas.print_figure( file_name,dpi=resolution )             

#make_widget( 0.01, [0.001,10.0], [[0.001,0.01,‘r’],[0.01,0.1,‘y’],[0.1,10.0,‘g’]], “Rx MOS (24h)”, [‘WLL to LAS’,‘LAS to WLL’,‘WLL to LAS’,‘LAS to WLL’], ‘log_gauge.png’, 100)

‘’’

if name==‘main’:

from pylab import figure, show



raw_value = -4.0

limits = [0.0001,1.0]

zone_colour = [[0.0001,0.001,'r'],[0.001,0.1,'y'],[0.1,1.0,'g']]

attribute_name = "Rx MOS (24h)"



graph_height = 1.6

graph_width  = 2.4

fig_height   = graph_height

fig_width    = graph_width

fig = figure( figsize=(fig_width, fig_height) )



rect = [(0.0/fig_width), (0.2/fig_height),

            (graph_width/fig_width), (graph_height/fig_height)]



gauge = Log_Gauge(fig, rect,

            xlim=( -0.1, graph_width+0.1 ),

            ylim=( -0.4, graph_height+0.1 ),

            xticks=[],

            yticks=[],

            )

gauge.set_axis_off()

fig.add_axes(gauge)



#show()

fig.canvas.print_figure('log_gauge',dpi=72)

‘’’