commit d80b57ecf852ca9ded4f0f636b41363ddbc3bad9 Author: Chris Proctor Date: Fri Jul 28 18:43:20 2023 -0400 Solution diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..96403d3 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +__pycache__/* diff --git a/constants.py b/constants.py new file mode 100644 index 0000000..0a79614 --- /dev/null +++ b/constants.py @@ -0,0 +1,3 @@ +PLOT_HEIGHT = 400 +PLOT_WIDTH = 400 +TICK_LENGTH = 5 diff --git a/generate_data.py b/generate_data.py new file mode 100644 index 0000000..4432013 --- /dev/null +++ b/generate_data.py @@ -0,0 +1,9 @@ +from random import randint, gauss + +def generate_data(n, xmin, xmax, slope, intercept, error): + sample = [] + for i in range(n): + x = randint(xmin, xmax) + y = round(gauss(intercept + x * slope, error)) + sample.append([x, y]) + return sample diff --git a/helpers.py b/helpers.py new file mode 100644 index 0000000..7780c54 --- /dev/null +++ b/helpers.py @@ -0,0 +1,6 @@ +from turtle import * + +def flyto(x, y): + penup() + goto(x, y) + pendown() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..5479979 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,15 @@ +[tool.poetry] +name = "lab-scatter" +version = "0.1.0" +description = "" +authors = ["Chris Proctor "] +readme = "README.md" + +[tool.poetry.dependencies] +python = "^3.10" +superturtle = "^0.1.0" + + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/scatterplot.py b/scatterplot.py new file mode 100644 index 0000000..daf45f8 --- /dev/null +++ b/scatterplot.py @@ -0,0 +1,113 @@ +# What needs to be taught? +# - return values +# - unpacking multiple return values +# - list comprehensions +# - named function arguments +# - after positional +# - like dictionaries +# - +# - modules + +# Parameters: +# - the actual drawing will be + +from turtle import * +from math import floor, ceil, log +import constants +from helpers import flyto +from superturtle.movement import no_delay +from generate_data import generate_data + +def draw_scatterplot(data, size=5, color="black"): + "Draws a scatter plot, showing the data" + prepare_screen() + draw_axes(data) + draw_points(data, color, size) + +def prepare_screen(): + """Sets up the + """ + screensize(400, 400) + setworldcoordinates(-20, -20, 420, 420) + +def draw_axes(data): + """Draws the scatter plot's axes. + """ + flyto(0, 0) + goto(0, constants.PLOT_HEIGHT) + flyto(0, 0) + goto(constants.PLOT_WIDTH, 0) + + y_values = get_y_values(data) + ymin, ymax = get_bounds(y_values) + draw_y_tick(0, ymin) + draw_y_tick(constants.PLOT_HEIGHT, ymax) + for tick in get_tick_range(y_values): + position = scale(tick, ymin, ymax, 0, constants.PLOT_HEIGHT) + draw_y_tick(position, tick) + + x_values = get_x_values(data) + xmin, xmax = get_bounds(x_values) + draw_x_tick(0, xmin) + draw_x_tick(constants.PLOT_WIDTH, xmax) + for tick in get_tick_range(x_values): + position = scale(tick, xmin, xmax, 0, constants.PLOT_WIDTH) + draw_x_tick(position, tick) + +def get_tick_range(values): + "Returns a range of positions for ticks" + vmin, vmax = get_bounds(values) + tick_interval = get_tick_interval(values) + first_tick = ceil(vmin / tick_interval) * tick_interval + print(tick_interval) + print(first_tick) + print(vmax) + return range(first_tick, vmax, tick_interval) + +def get_tick_interval(values): + "" + vmin, vmax = get_bounds(values) + log_span = log(vmax - vmin, 10) + return 10 ** floor(log_span) + +def draw_points(data, color, size): + xmin, xmax = get_bounds(get_x_values(data)) + ymin, ymax = get_bounds(get_y_values(data)) + for x, y in data: + sx = scale(x, xmin, xmax, 0, constants.PLOT_WIDTH) + sy = scale(y, ymin, ymax, 0, constants.PLOT_HEIGHT) + draw_point(sx, sy, color, size) + +def draw_point(x, y, color, size): + flyto(x, y) + dot(size, color) + +def get_bounds(data): + return min(data), max(data) + +def get_x_values(data): + return [x for x, y, in data] + +def get_y_values(data): + return [y for x, y in data] + +def draw_y_tick(position, label): + flyto(0, position) + goto(-constants.TICK_LENGTH, position) + write(label, align='right') + +def draw_x_tick(position, label): + flyto(position, 0) + goto(position, -constants.TICK_LENGTH) + flyto(position, -constants.TICK_LENGTH - 10) + write(label, align='center') + +def scale(value, domain_min, domain_max, range_min, range_max): + ratio = (value - domain_min) / (domain_max - domain_min) + return range_min + ratio * (range_max - range_min) + +with no_delay(): + data = generate_data(50, 10, 500, 25, 100, 1000) + draw_scatterplot(data, size=5, color="blue") + hideturtle() +input()