Die Besonderheiten sind:
- Es können Ränder für (zukünftige) Skalen gelassen werden
- Bei Negativwerten kann eine NullLinie gezeichnet werden
- Bei der Zeichenfläche in Tkinter (canvas) wird die Eben von Links oben aufgespannt deswegen wird der Graph vertikal um die Canvashöhe nach unten verschoben und einmal umgeklappt.
* Ich will die Klasse so allgemein halten, wie möglich.
Denn an meinem Kontolister, in dessen Rahmen diese Klasse entstanden ist, will ich die wichtigsten GUI's (tkinter, GTK2, QT, WX) ausprobieren.
Meine Fragen:
1. Die Zeilen 148 und 149 habe ich aufgeteilt, damit ich unter den 80 Zeichen pro Zeile bleibe. Wie hättet ihr euch entschieden?
2. Wie hättet ihr den Test / Demo Abschnitt implementiert? Als eigene Klasse, als Funktion der Klasse Graf oder so wie hier ab Zeile 181?
Cu Sebastian
Edit:
Typos
Code: Alles auswählen
#!/usr/bin/python
# -*- encoding: latin-1 -*-
# todo:
# - Errorhandling if init values are not set
# - direkt auf (Klassenvariablen zugreifen oder beim Aufruf übergeben?)
# - in 2 Klassen aufteilen:
# - - graph-core (simple_graph)
# - - graph: inherits from graph-core plus borders, scales ()
# - check border_bottom < canvas_height --> gen_values_2_draw()
# - check border_left < canvas_width --> gen_values_2_draw()
# done:
# 004 - new Logic: regenerate all values when one is changed
# 003 -> it's working :-)
################-------#############
## imports ##
################-------#############
# following imports are called when running stand alone (demo mode)
#import Tkinter
#import time
class Graph:
''' todo: write this docstring '''
def __init__(self, values = [1,2,3]):
''' All these values representing pixel on a drawing area(Tkinter canvas)
Right now the funktion "upside_down" is called by default,
later there may bee a choice
- border_bottom (free space to draw a time(horizontal) scale,type=float)
- border_left (free space to draw an y scale, type = float)
- canvas_height (type = float)
- canvas_width (type = float)
- graph_upside_down (type = bool) # currently unused!!!!!!!!!!!!!!!!
- step_width (horizontal distance between two y values, type = float)
- values (y input values; type = List of floats)
- values_2_draw (y output values; type = List of floats)
- zero_line (
- - min(values_2_draw) < 0: y value(type=float) to draw a line over y=0
- - min(values_2_draw) >= 0: zero_line = None)'''
self.border_bottom = 10.0
self.border_left = 10.0
self.canvas_height = 100.0
self.canvas_width = 200.0
self.graph_upside_down = True # rename to do_upside_down ?
self.step_width = 1.0
self.values = values
self.values_2_draw = None
self.zero_line = None
self.gen_values_2_draw()
################-------#############
## setters ##
################-------#############
def set_borders(self, border_left, border_bottom):
''' todo: write this docstring '''
# todo: make shure values are saved as floats
self.border_bottom = border_bottom
self.border_left = border_left
self.gen_values_2_draw()
def set_canvas_dimensions(self, canvas_height, canvas_width):
''' todo: write this docstring '''
# todo: make shure values are saved as floats
# obsolete?
self.canvas_height = canvas_height
self.canvas_width = canvas_width
self.gen_values_2_draw()
def set_canvas_height(self, new_height):
''' todo: write this docstring'''
self.canvas_height = new_height
self.gen_values_2_draw()
def set_canvas_width(self, new_width):
''' todo: write this docstring'''
self.canvas_width = new_width
self.gen_values_2_draw()
def set_values(self, values):
''' todo: write this docstring '''
# todo: make shure values are saved as floats
self.values = values
self.gen_values_2_draw()
def set_upside_down(self, upside_down_bool):
''' todo: write this docstring '''
# todo: make shure value is bool
self.graph_upside_down = upside_down_bool
self.gen_values_2_draw()
################-------#############
## getters ##
################-------#############
def get_border_left(self):
''' todo: write this docstring
- return type: float'''
return self.border_left
def get_canvas_height(self):
''' todo: write this docstring
- return type: float'''
return self.canvas_height
def get_canvas_width(self):
''' todo: write this docstring
- return type: float'''
return self.canvas_width
def get_step_width(self):
''' todo: write this docstring '''
return self.step_width
def get_values_2_draw(self):
''' todo: write this docstring
- return type: list of floats'''
return self.values_2_draw
############-------------###########
## div functions ##
############-------------###########
def gen_values_2_draw(self):
''' hidden function?
when a set_* Function is called "gen_values_2_draw" updates:
- self.values_2_draw (list of floats) and
- self.zero_line (bool)
- self.step_width (float)'''
drawable_height = self.canvas_height - 1.0 * self.border_bottom
max_distanz = (max(self.values) - min(self.values))
k_factor = drawable_height / max_distanz
new_values = [round(i * k_factor,1) for i in self.values]
self.zero_line = None # make shure it is really None -- still needet?
if min(new_values) < 0:
min_value = min(new_values)
self.zero_line = 0 - min_value
new_values = [i - min_value for i in new_values]
self.values_2_draw = self.upside_down(new_values, self.canvas_height)
self.step_width = ( float(self.canvas_width - self.border_left)
/ len(self.values) )
def upside_down(self, values, canvas_height):
""" hidden function?
bla"""
return_values = [canvas_height - i - self.border_bottom for i in values]
if self.zero_line:
self.zero_line = canvas_height - self.zero_line - self.border_bottom
else:
self.zero_line = None
return return_values
###############-------##############
## testing ##
###############-------##############
def print_all_values(self):
'''Just for testing purposes.
It simply prints all values'''
print "\nself.values: ", self.values
print "self.values_2_draw: ", self.values_2_draw
print "self.zero_line: ", self.zero_line
print "self.border_bottom: ", self.border_bottom
print "self.border_left: ", self.border_left
print "self.canvas_height: ", self.canvas_height
print "self.canvas_width: ", self.canvas_width
print "self.graph_upside_down: ", self.graph_upside_down
print "self.step_width: ", self.step_width
if __name__ == '__main__':
print "\n Demo in main gestartet\n"
import Tkinter
import time
rect_height = 102
rect_width = 109
werte = [1, 30, -40, 30, 50, 130, 90]
g = Graph(werte)
g.print_all_values()
g.set_canvas_dimensions(rect_height, rect_width)
g.print_all_values()
hauptfenster = Tkinter.Tk()
canvas = Tkinter.Canvas(hauptfenster,
width = rect_width,
height = rect_height,
bg = "white")
canvas.pack()
if g.zero_line:
canvas.create_line( 0, g.zero_line,
rect_width, g.zero_line,
width = 1,
fill = "red")
x_start = g.get_border_left()
for y in g.get_values_2_draw():
canvas.create_line( x_start, y, x_start, y + 5,
width = 2)
x_start += g.get_step_width()
canvas.update()
time.sleep(0.1) # "animated" drawing :-)
hauptfenster.mainloop()
g.set_values([1, 30, -40, 30, 50, -130, 90])
g.print_all_values()
print '\nProgramm ganz zu Ende\n'