Gauges and Meters - Vert/Horiz Meter.
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 Meter widget draws a linear meter, either horizontally or vertically. You supply the direction, limits,
shaded regions, names and the current value, and invoke it like this:
from pylab import figure, show
raw_value = -4.0
raw_limits = [-10.0,10.0,5,1]
raw_zones = [[-10.0,0.0,'r'],[0.0,5.0,'y'],[5.0,10.0,'g']]
attribute_name = "Rx MOS (24h)"
s_length = 0.3
p_length = 2.0
fig_height = s_length + 1.0
fig_width = p_length + 0.4
fig = figure( figsize=(fig_width, fig_height) )
rect = [(0.2/fig_width), (0.5/fig_height),
(p_length/fig_width), (s_length/fig_height)]
meter = H_Meter(fig, rect,
xlim=( -0.1, p_length+0.1 ),
ylim=( -0.4, s_length+0.1 ),
xticks=[],
yticks=[],
)
meter.set_axis_off()
fig.add_axes(meter)
show()
“”"
from future import division
from matplotlib.figure import Figure
from matplotlib.axes import Axes
import math
import types
from math import pi
class Meter(Axes):
def __init__(self, vertical, raw_value, raw_limits, raw_zones, attribute_name, field_names, file_name, resolution, p_length, s_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( ((raw_limits[2]/raw_limits[3]) % 1.0) * raw_limits[3] == 0 ): #There must be an integer number of minor ticks for each major tick
raise ValueError('bad_tick_spacing_exception')
if( raw_limits[2] <= 0 or raw_limits[3] <= 0 or raw_limits[2] < raw_limits[3] or raw_limits[3] > abs(raw_limits[1]-raw_limits[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]
#Adjust the scaling
self.scaled_limits = []
for limit in raw_limits:
self.scaled_limits.append( limit * p_length / (raw_limits[1]-raw_limits[0]))
#Stuff all of the variables into self.
self.vertical = vertical
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.p_length = p_length
self.s_length = s_length
#Draw the meter
self.graph_center = ((self.scaled_limits[1]+self.scaled_limits[0])/2)
for zone in raw_zones:
self.draw_bar( zone, False)
self.draw_bar( None, True)
self.draw_ticks()
self.draw_needle()
if( self.vertical ):
self.text( self.s_length/2, self.scaled_limits[0]-0.1, self.attribute_name, size=12, va='top', ha='center')
else:
self.text( self.graph_center, self.s_length+0.25, self.attribute_name, size=12, va='bottom', ha='center')
def draw_bar( self, zone, border):
if( border ):
start = self.scaled_limits[0]
end = self.scaled_limits[1]
else:
start = (zone[0] * self.p_length / (self.raw_limits[1]-self.raw_limits[0]))
end = (zone[1] * self.p_length / (self.raw_limits[1]-self.raw_limits[0]))
colour = zone[2]
if( not self.graph_positive ):
start = -start
end = -end
s_vect = [ 0.0, 0.0, self.s_length, self.s_length ]
p_vect = [ start, end, end, start ]
if( border ):
#Close the loop
p_vect.append(start)
s_vect.append(0.0)
if( self.vertical ):
p = self.plot(s_vect, p_vect, 'b-', color='black', linewidth=1.5)
else:
p = self.plot(p_vect, s_vect, 'b-', color='black', linewidth=1.5)
else:
if( self.vertical ):
p = self.fill(s_vect, p_vect, colour, linewidth=0.0, alpha=0.4)
else:
p = self.fill(p_vect, s_vect, colour, linewidth=0.0, alpha=0.4)
def draw_needle( self ):
if( self.raw_value == None ):
if( self.vertical ):
self.text( (self.s_length + 0.05), self.graph_center, "N/A", size=10, va='center', ha='left')
else:
self.text( self.graph_center, (self.s_length + 0.05), "N/A", size=10, va='bottom', ha='center')
else:
#Clamp the value to the limits
value = self.raw_value * self.p_length / (self.raw_limits[1]-self.raw_limits[0])
if( self.raw_value < self.raw_limits[0] ):
value = self.raw_limits[0] * self.p_length / (self.raw_limits[1]-self.raw_limits[0])
if( self.raw_value > self.raw_limits[1] ):
value = self.raw_limits[1] * self.p_length / (self.raw_limits[1]-self.raw_limits[0])
if( self.vertical ):
self.text( (self.s_length + 0.05), value, "%.2f" % self.raw_value, size=10, va='center', ha='left')
else:
self.text( value, (self.s_length + 0.05), "%.2f" % self.raw_value, size=10, va='bottom', ha='center')
if( not self.graph_positive ):
value = -value
s_vect = [ self.s_length/2, self.s_length, self.s_length ]
p_vect = [ value + 0.00, value - 0.05, value + 0.05 ]
if( self.vertical ):
self.fill(s_vect, p_vect, 'black')
else:
self.fill(p_vect, s_vect, 'black')
def draw_ticks( self ):
if( self.graph_positive ):
offset = self.scaled_limits[0]
else:
offset = self.scaled_limits[1]
i = 0
j = self.raw_limits[0]
while( i*self.scaled_limits[3] + self.scaled_limits[0] <= self.scaled_limits[1] ):
if( i % (self.scaled_limits[2]/self.scaled_limits[3]) == 0):
tick_length = self.s_length
if( self.vertical ):
if( type(self.raw_limits[2]) is types.FloatType ):
self.text( -0.05, offset, "%.2f" % j, size=10, va='center', ha='right')
else:
self.text( -0.05, offset, "%d" % int(j), size=10, va='center', ha='right')
else:
tick_length = self.s_length
if( type(self.raw_limits[2]) is types.FloatType ):
self.text( offset, -0.05, "%.2f" % j, size=10, va='top', ha='center')
else:
self.text( offset, -0.05, "%d" % int(j), size=10, va='top', ha='center')
j += self.raw_limits[2]
else:
tick_length = self.s_length * 0.2
s_vect = [ 0.0, tick_length ]
p_vect = [ offset, offset ]
if( self.vertical ):
p = self.plot(s_vect, p_vect, 'b-', linewidth=1, color='black', alpha=0.2)
else:
p = self.plot(p_vect, s_vect, 'b-', linewidth=1, color='black', alpha=0.2)
i += 1
if( self.graph_positive ):
offset += self.scaled_limits[3]
else:
offset -= self.scaled_limits[3]
if( i % (self.scaled_limits[2]/self.scaled_limits[3]) == 0):
if( self.vertical ):
if( type(self.raw_limits[2]) is types.FloatType ):
self.text( -0.01, offset, "%.2f" % j, size=10, va='top', ha='center')
else:
self.text( -0.01, offset, "%d" % int(j), size=10, va='top', ha='center')
else:
if( type(self.raw_limits[2]) is types.FloatType ):
self.text( offset, -0.1, "%.2f" % j, size=10, va='top', ha='center')
else:
self.text( offset, -0.1, "%d" % int(j), size=10, va='top', ha='center')
def make_widget( vertical, raw_value, raw_limits, raw_zones, attribute_name, field_names, file_name, resolution=72 ):
from pylab import figure, show, savefig
p_length = 2.0 # Length of the Primary axis
s_length = 0.3 # Length of the Secondary axis
if( vertical ):
fig_height = p_length + 0.6
fig_width = s_length + 1.0
fig = figure( figsize=(fig_width, fig_height) )
rect = [(0.5/fig_width), (0.4/fig_height), (s_length/fig_width), (p_length/fig_height)]
meter = Meter(vertical, raw_value,
raw_limits, raw_zones,
attribute_name, field_names,
file_name, resolution,
p_length, s_length,
fig, rect,
xlim=( -0.2, s_length+0.1 ),
ylim=( -0.1, p_length+0.1 ),
xticks=[],
yticks=[]
)
else:
fig_height = s_length + 1.0
fig_width = p_length + 0.4
fig = figure( figsize=(fig_width, fig_height) )
rect = [(0.2/fig_width), (0.5/fig_height), (p_length/fig_width), (s_length/fig_height)]
meter = Meter(vertical, raw_value,
raw_limits, raw_zones,
attribute_name, field_names,
file_name, resolution,
p_length, s_length,
fig, rect,
xlim=( -0.1, p_length+0.1 ),
ylim=( -0.4, s_length+0.1 ),
xticks=[],
yticks=[],
)
meter.set_axis_off()
fig.add_axes(meter)
show()
fig.canvas.print_figure( file_name,dpi=resolution )
#make_widget( False, -3.0, [-10.0,10.0,5,1], [[-10.0,0.0,‘r’],[0.0,5.0,‘y’],[5.0,10.0,‘g’]], “Rx MOS (24h)”, [‘WLL to LAS’,‘LAS to WLL’,‘WLL to LAS’,‘LAS to WLL’], ‘meter.png’, 100)
‘’’
if name==‘main’:
from pylab import figure, show, savefig
vertical = True
raw_value = None
raw_limits = [-10.0,10.0,5,1]
raw_zones = [[-10.0,0.0,'r'],[0.0,5.0,'y'],[5.0,10.0,'g']]
attribute_name = "Rx MOS (24h)"
p_length = 2.0 # Length of the Primary axis
s_length = 0.3 # Length of the Secondary axis
if( vertical ):
fig_height = p_length + 0.6
fig_width = s_length + 1.0
fig = figure( figsize=(fig_width, fig_height) )
rect = [(0.5/fig_width), (0.4/fig_height), (s_length/fig_width), (p_length/fig_height)]
meter = Meter(fig, rect,
xlim=( -0.2, s_length+0.1 ),
ylim=( -0.1, p_length+0.1 ),
xticks=[],
yticks=[],
)
else:
fig_height = s_length + 1.0
fig_width = p_length + 0.4
fig = figure( figsize=(fig_width, fig_height) )
rect = [(0.2/fig_width), (0.5/fig_height), (p_length/fig_width), (s_length/fig_height)]
meter = Meter(fig, rect,
xlim=( -0.1, p_length+0.1 ),
ylim=( -0.4, s_length+0.1 ),
xticks=[],
yticks=[],
)
meter.set_axis_off()
fig.add_axes(meter)
show()
fig.canvas.print_figure('meter',dpi=72)
‘’’