Datapoint improvements.
- Chart title - Can use different point color for each layer of points - Prettier indentation
This commit is contained in:
parent
0dec7cbcff
commit
7fc972920f
1 changed files with 127 additions and 57 deletions
|
@ -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.window_height,
|
||||||
|
fill=self.color_outbound,
|
||||||
|
)
|
||||||
|
self.c.create_rectangle(
|
||||||
|
self.margin_x,
|
||||||
|
self.margin_y,
|
||||||
self.window_width - self.margin_x,
|
self.window_width - self.margin_x,
|
||||||
self.window_height - self.margin_y,
|
self.window_height - self.margin_y,
|
||||||
fill='SystemButtonFace')
|
fill='SystemButtonFace',
|
||||||
self.coordinateslabel = self.c.create_text(8, 8, text='xy',
|
)
|
||||||
|
self.coordinateslabel = self.c.create_text(
|
||||||
|
8,
|
||||||
|
8,
|
||||||
|
text='xy',
|
||||||
anchor='nw',
|
anchor='nw',
|
||||||
font=('Consolas', 10))
|
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:
|
||||||
|
for point in layer_points:
|
||||||
p = self.transform_coord(point[0], point[1])
|
p = self.transform_coord(point[0], point[1])
|
||||||
x = p[0]
|
x = p[0]
|
||||||
y = p[1]
|
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):
|
||||||
|
|
Loading…
Reference in a new issue