Datapoint improvements.

- Chart title
- Can use different point color for each layer of points
- Prettier indentation
master
voussoir 2021-03-25 14:22:59 -07:00
parent 0dec7cbcff
commit 7fc972920f
No known key found for this signature in database
GPG Key ID: 5F7554F8C26DACCB
1 changed files with 127 additions and 57 deletions

View File

@ -3,13 +3,19 @@ import tkinter
class DataPoint: class DataPoint:
def __init__(self, width=720, height=480, autostart=False): def __init__(
self,
width=720,
height=480,
autostart=False,
title=None,
):
self.title = title
self.windowtitle = 'DataPoint' self.windowtitle = 'DataPoint'
self.color_outbound = '#999' self.color_outbound = '#999'
self.color_crossbar = '#bbb' self.color_crossbar = '#bbb'
self.color_point = '#000' self.color_point = '#000'
self.color_point_out = '#000'
self.crossbar_count = 10 self.crossbar_count = 10
self.point_diameter = 4 self.point_diameter = 4
self.margin = 0.10 self.margin = 0.10
@ -20,10 +26,9 @@ class DataPoint:
self.t.title(self.windowtitle) self.t.title(self.windowtitle)
self.w = width self.w = width
self.h = height self.h = height
self.windowx = (self.screen_width-self.w) / 2 self.windowx = int((self.screen_width-self.w) / 2)
self.windowy = ((self.screen_height-self.h) / 2) - 27 self.windowy = int(((self.screen_height-self.h) / 2) - 27)
self.geometrystring = '%dx%d+%d+%d' % (self.w, self.h, self.geometrystring = f'{self.w}x{self.h}+{self.windowx}+{self.windowy}'
self.windowx, self.windowy)
self.t.geometry(self.geometrystring) self.t.geometry(self.geometrystring)
self.countdown = -1 self.countdown = -1
@ -106,7 +111,7 @@ class DataPoint:
if self.countdown == 0: if self.countdown == 0:
# Plot. # Plot.
if not self.resized: if not self.resized:
self.plot_points([]) self.redraw()
self.resized = True self.resized = True
return return
@ -114,7 +119,9 @@ class DataPoint:
''' '''
Set the DataPoint's grid attributes back to None. Set the DataPoint's grid attributes back to None.
''' '''
self.POINTS = set() self.total_points = set()
self.point_layers = []
self.graph_layer = 0
self.lowest_x = None self.lowest_x = None
self.highest_x = None self.highest_x = None
self.lowest_y = None self.lowest_y = None
@ -146,24 +153,48 @@ class DataPoint:
''' '''
Draw the dark margin. Draw the dark margin.
''' '''
self.c.create_rectangle(0, 0, self.window_width, self.window_height, self.c.create_rectangle(
fill=self.color_outbound) 0,
self.c.create_rectangle(self.margin_x, self.margin_y, 0,
self.window_width - self.margin_x, self.window_width,
self.window_height - self.margin_y, self.window_height,
fill='SystemButtonFace') fill=self.color_outbound,
self.coordinateslabel = self.c.create_text(8, 8, text='xy', )
anchor='nw', self.c.create_rectangle(
font=('Consolas', 10)) self.margin_x,
self.margin_y,
self.window_width - self.margin_x,
self.window_height - self.margin_y,
fill='SystemButtonFace',
)
self.coordinateslabel = self.c.create_text(
8,
8,
text='xy',
anchor='nw',
font=('Consolas', 10),
)
def draw_title(self):
if not self.title:
return
self.c.create_text(
int(self.window_width / 2),
int(self.margin_y / 2),
anchor='center',
text=self.title,
font=('Consolas', 20),
)
def draw_labels(self): def draw_labels(self):
''' '''
Draw the text labels along the axes. Draw the text labels along the axes.
''' '''
if len(self.POINTS) == 0: if len(self.total_points) == 0:
return return
if len(self.POINTS) == 1: if len(self.total_points) == 1:
p = next(iter(self.POINTS)) p = next(iter(self.total_points))
if p == self.origin: if p == self.origin:
return return
lp = self.transform_coord(*p) lp = self.transform_coord(*p)
@ -182,11 +213,19 @@ class DataPoint:
if self.highest_x != self.lowest_x: if self.highest_x != self.lowest_x:
# LOW X # LOW X
self.c.create_text(low_x+5, low_y+5, self.c.create_text(
text=str(round(self.lowest_x, 4)), anchor='nw') low_x+5,
low_y+5,
text=str(round(self.lowest_x, 4)),
anchor='nw',
)
# FAR X # FAR X
self.c.create_text(hi_x+5, low_y+5, self.c.create_text(
text=str(round(self.highest_x, 4)), anchor='nw') hi_x+5,
low_y+5,
text=str(round(self.highest_x, 4)),
anchor='nw',
)
increment_x = (self.highest_x - self.lowest_x) / self.crossbar_count increment_x = (self.highest_x - self.lowest_x) / self.crossbar_count
crossbartop = self.margin_y crossbartop = self.margin_y
@ -194,31 +233,49 @@ class DataPoint:
for x in range(1, self.crossbar_count): for x in range(1, self.crossbar_count):
x = (x * increment_x) + self.lowest_x x = (x * increment_x) + self.lowest_x
p = self.transform_coord(x, self.lowest_y) p = self.transform_coord(x, self.lowest_y)
self.c.create_line(p[0], crossbartop, p[0], crossbarbot, self.c.create_line(
fill=self.color_crossbar) p[0],
crossbartop,
p[0],
crossbarbot,
fill=self.color_crossbar,
)
x = str(round(x, 3)) x = str(round(x, 3))
self.c.create_text(p[0], low_y+5, text=x, anchor='n') self.c.create_text(p[0], low_y+5, text=x, anchor='n')
if self.highest_y != self.lowest_y: if self.highest_y != self.lowest_y:
# LOW Y # LOW Y
self.c.create_text(low_x-5, low_y, self.c.create_text(
text=str(round(self.lowest_y, 4)), anchor='se') low_x-5,
low_y,
text=str(round(self.lowest_y, 4)),
anchor='se',
)
# UPPER Y # UPPER Y
self.c.create_text(low_x-5, hi_y, self.c.create_text(
text=str(round(self.highest_y, 4)), anchor='e') low_x-5,
hi_y,
text=str(round(self.highest_y, 4)),
anchor='e',
)
increment_y = (self.highest_y - self.lowest_y) / self.crossbar_count increment_y = (self.highest_y - self.lowest_y) / self.crossbar_count
crossbarlef = self.margin_x crossbarlef = self.margin_x
crossbarrgt = self.window_width - self.margin_x crossbarrgt = self.window_width - self.margin_x
for y in range(1, self.crossbar_count): for y in range(1, self.crossbar_count):
y = (y * increment_y) + self.lowest_y y = (y * increment_y) + self.lowest_y
p = self.transform_coord(self.lowest_x, y) p = self.transform_coord(self.lowest_x, y)
self.c.create_line(crossbarlef, p[1], crossbarrgt, p[1], self.c.create_line(
fill=self.color_crossbar) crossbarlef,
p[1],
crossbarrgt,
p[1],
fill=self.color_crossbar,
)
y = str(round(y, 3)) y = str(round(y, 3))
self.c.create_text(low_x-5, p[1], text=y, anchor='e') self.c.create_text(low_x-5, p[1], text=y, anchor='e')
def draw_coordinateslabel(self, event): def draw_coordinateslabel(self, event):
if len(self.POINTS) < 2: if len(self.total_points) < 2:
return return
l = self.transform_coord(event.x, event.y, reverse=True) l = self.transform_coord(event.x, event.y, reverse=True)
l = '%03.12f, %03.12f' % l l = '%03.12f, %03.12f' % l
@ -267,58 +324,71 @@ class DataPoint:
return (x, y) return (x, y)
def plot_points(self, points=[]): def plot_points(self, points, point_color=None):
''' '''
Plot points onto the canvas. Plot points onto the canvas.
var points = list, where each element is a 2-length tuple, where [0] var points = list, where each element is a 2-length tuple, where [0]
is x and [1] is y coordinate. is x and [1] is y coordinate.
''' '''
original_len = len(self.POINTS) if point_color is None:
for point in points: point_color = self.color_point
self.POINTS.add(tuple(point))
layer_points = set()
for point in points:
point = tuple(point)
self.total_points.add(point)
layer_points.add(point)
self.point_layers.append((layer_points, point_color))
self.redraw()
def redraw(self):
self.clear_screen() self.clear_screen()
self.draw_margin() self.draw_margin()
if len(self.POINTS) == 0: self.draw_title()
return
xs = [point[0] for point in self.POINTS] xs = [point[0] for point in self.total_points]
ys = [point[1] for point in self.POINTS] ys = [point[1] for point in self.total_points]
self.lowest_x = min(xs) self.lowest_x = min(xs)
self.highest_x = max(xs) self.highest_x = max(xs)
self.lowest_y = min(ys) self.lowest_y = min(ys)
self.highest_y = max(ys) self.highest_y = max(ys)
self.span_x = abs(self.highest_x - self.lowest_x) self.span_x = abs(self.highest_x - self.lowest_x)
self.span_x = max(1, self.span_x)
self.span_y = abs(self.highest_y - self.lowest_y) self.span_y = abs(self.highest_y - self.lowest_y)
if self.span_x == 0: self.span_y = max(1, self.span_y)
self.span_x = 1
if self.span_y == 0:
self.span_y = 1
self.drawable_w = self.window_width - (2 * self.margin_x) self.drawable_w = self.window_width - (2 * self.margin_x)
self.drawable_h = self.window_height - (2 * self.margin_y) self.drawable_h = self.window_height - (2 * self.margin_y)
self.draw_labels() self.draw_labels()
if len(self.POINTS) > 1 or self.origin in self.POINTS: if len(self.total_points) > 1 or self.origin in self.total_points:
p = self.transform_coord(*self.origin) p = self.transform_coord(*self.origin)
self.draw_axes(*p) self.draw_axes(*p)
for point in self.POINTS: for (layer_points, point_color) in self.point_layers:
p = self.transform_coord(point[0], point[1]) for point in layer_points:
x = p[0] p = self.transform_coord(point[0], point[1])
y = p[1] x = p[0]
y = p[1]
r = self.point_diameter / 2 r = self.point_diameter / 2
self.c.create_oval(x-r, y-r, x+r, y+r, fill=self.color_point, self.c.create_oval(
outline=self.color_point) x-r,
y-r,
x+r,
y+r,
fill=point_color,
outline=point_color,
)
self.c.update() self.c.update()
def plot_point(self, x, y):
self.plot_points([[x, y]])
def set_origin(self, x, y): def set_origin(self, x, y):
self.origin = (x, y) self.origin = (x, y)
self.plot_points([]) self.redraw()
def example(function): def example(function):