Skip to content

Widget cartesian tweaks #64

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
184 changes: 146 additions & 38 deletions adafruit_displayio_layout/widgets/cartesian.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,8 +310,6 @@ def __init__(
self.append(self._screen_tilegrid)
self.append(self._corner_tilegrid)

self._update_line = True

self._pointer = None
self._circle_palette = None
self.plot_line_point = None
Expand Down Expand Up @@ -389,10 +387,12 @@ def _draw_ticks(self) -> None:

if self._subticks:
if i in subticks:
# calc subtick_line_height; force min lineheigt to 1.
subtick_line_height = max(1, self._tick_line_height // 2)
rectangle_helper(
text_dist,
self._axes_line_thickness,
self._tick_line_height // 2,
subtick_line_height,
1,
self._axesx_bitmap,
1,
Expand Down Expand Up @@ -457,54 +457,162 @@ def _draw_pointers(self, x: int, y: int) -> None:

self.append(self._pointer)

def update_pointer(self, x: int, y: int) -> None:
"""updater_pointer function
helper function to update pointer in the plane
def _calc_local_xy(self, x: int, y: int) -> (int, int):
local_x = (
int((x - self._xrange[0]) * self._factorx * self._valuex) + self._nudge_x
)
# details on `+ (self.height - 1)` :
# the bitmap is set to self.width & self.height
# but we are only allowed to draw to pixels 0..height-1 and 0..width-1
local_y = (
int((self._yrange[0] - y) * self._factory * self._valuey)
+ (self.height - 1)
+ self._nudge_y
)
return (local_x, local_y)

def _check_local_x_in_range(self, local_x):
return 0 <= local_x < self.width

def _check_local_y_in_range(self, local_y):
return 0 <= local_y < self.height

def _check_local_xy_in_range(self, local_x, local_y):
return self._check_local_x_in_range(local_x) and self._check_local_y_in_range(
local_y
)

def _check_x_in_range(self, x):
return self._xrange[0] <= x <= self._xrange[1]

def _check_y_in_range(self, y):
return self._yrange[0] <= y <= self._yrange[1]

def _check_xy_in_range(self, x, y):
return self._check_x_in_range(x) and self._check_y_in_range(y)

def _add_point(self, x: int, y: int) -> None:
"""_add_point function
helper function to add a point to the graph in the plane
:param int x: ``x`` coordinate in the local plane
:param int y: ``y`` coordinate in the local plane
:return: None
rtype: None
"""
local_x = int((x - self._xrange[0]) * self._factorx) + self._nudge_x
local_y = (
int((self._yrange[0] - y) * self._factory) + self.height + self._nudge_y
print("")
print(
"xy: ({: >4}, {: >4}) "
"_xrange: ({: >4}, {: >4}) "
"_yrange: ({: >4}, {: >4}) "
"".format(
x,
y,
self._xrange[0],
self._xrange[1],
self._yrange[0],
self._yrange[1],
)
)

if local_x >= 0 or local_y <= 100:
if self._update_line:
self._draw_pointers(local_x, local_y)
self._update_line = False
local_x, local_y = self._calc_local_xy(x, y)
print(
"local_*: ({: >4}, {: >4}) "
" width: ({: >4}, {: >4}) "
" height: ({: >4}, {: >4}) "
"".format(
local_x,
local_y,
0,
self.width,
0,
self.height,
)
)
if self._check_xy_in_range(x, y):
if self._check_local_xy_in_range(local_x, local_y):
if self.plot_line_point is None:
self.plot_line_point = []
self.plot_line_point.append((local_x, local_y))
else:
self._pointer.x = local_x
self._pointer.y = local_y
# for better error messages we check in detail what failed...
# this should never happen:
# we already checked the range of the input values.
# but in case our calculation is wrong we handle this case to..
if not self._check_local_x_in_range(local_x):
raise ValueError(
"local_x out of range: "
"local_x:{: >4}; _xrange({: >4}, {: >4})"
"".format(
local_x,
0,
self.width,
)
)
if not self._check_local_y_in_range(local_y):
raise ValueError(
"local_y out of range: "
"local_y:{: >4}; _yrange({: >4}, {: >4})"
"".format(
local_y,
0,
self.height,
)
)
else:
# for better error messages we check in detail what failed...
if not self._check_x_in_range(x):
raise ValueError(
"x out of range: "
"x:{: >4}; xrange({: >4}, {: >4})"
"".format(
x,
self._xrange[0],
self._xrange[1],
)
)
if not self._check_y_in_range(y):
raise ValueError(
"y out of range: "
"y:{: >4}; yrange({: >4}, {: >4})"
"".format(
y,
self._yrange[0],
self._yrange[1],
)
)

def _set_plotter_line(self) -> None:
self.plot_line_point = []
def update_pointer(self, x: int, y: int) -> None:
"""updater_pointer function
helper function to update pointer in the plane
:param int x: ``x`` coordinate in the local plane
:param int y: ``y`` coordinate in the local plane
:return: None
rtype: None
"""
self._add_point(x, y)
if not self._pointer:
self._draw_pointers(
self.plot_line_point[-1][0],
self.plot_line_point[-1][1],
)
else:
self._pointer.x = self.plot_line_point[-1][0]
self._pointer.y = self.plot_line_point[-1][1]

def update_line(self, x: int, y: int) -> None:
"""updater_line function
helper function to update pointer in the plane
helper function to update line in the plane
:param int x: ``x`` coordinate in the local plane
:param int y: ``y`` coordinate in the local plane
:return: None
rtype: None
"""
local_x = int((x - self._xrange[0]) * self._factorx) + self._nudge_x
local_y = (
int((self._yrange[0] - y) * self._factory) + self.height + self._nudge_y
)
if x < self._xrange[1] and y < self._yrange[1]:
if local_x > 0 or local_y < 100:
if self._update_line:
self._set_plotter_line()
self.plot_line_point.append((local_x, local_y))
self._update_line = False
else:
bitmaptools.draw_line(
self._screen_bitmap,
self.plot_line_point[-1][0],
self.plot_line_point[-1][1],
local_x,
local_y,
1,
)
self._add_point(x, y)
if len(self.plot_line_point) > 1:
bitmaptools.draw_line(
self._screen_bitmap,
self.plot_line_point[-2][0],
self.plot_line_point[-2][1],
self.plot_line_point[-1][0],
self.plot_line_point[-1][1],
1,
)
69 changes: 69 additions & 0 deletions examples/displayio_layout_cartesian_dev.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# SPDX-FileCopyrightText: 2021 Stefan Krüger
#
# SPDX-License-Identifier: MIT
#############################
"""
This is a basic demonstration of a Cartesian widget for line-ploting
"""

import time
import board
import displayio
from adafruit_displayio_layout.widgets.cartesian import Cartesian

# create the display on the PyPortal or Clue or PyBadge(for example)
display = board.DISPLAY
# otherwise change this to setup the display
# for display chip driver and pinout you have (e.g. ILI9341)

# pybadge display: 160x128
# Create a Cartesian widget
# https://circuitpython.readthedocs.io/projects/displayio-layout/en/latest/api.html#module-adafruit_displayio_layout.widgets.cartesian
my_plane = Cartesian(
x=11, # x position for the plane
y=0, # y plane position
width=140, # display width
height=110, # display height
xrange=(0, 10), # x range
yrange=(0, 10), # y range
major_tick_stroke=1, # ticks width in pixels
major_tick_length=2, # ticks length in pixels
axes_stroke=1, # axes lines width in pixels
axes_color=0x10A0A0, # axes line color
subticks=True,
)

my_group = displayio.Group()
my_group.append(my_plane)
display.show(my_group) # add high level Group to the display

data = [
# (0, 0),
(1, 1),
# (1, 15), # create out of range error
(2, 1),
(2, 2),
(3, 3),
(4, 3),
(4, 4),
(5, 5),
(6, 5),
(6, 6),
(7, 7),
(8, 7),
(8, 8),
(9, 9),
(10, 9),
(10, 10),
]

print("examples/displayio_layout_cartesian_lineplot.py")

my_plane.update_line(0, 0)
for x, y in data:
my_plane.update_line(x, y)
my_plane.update_pointer(x, y)
time.sleep(0.5)

while True:
pass
52 changes: 52 additions & 0 deletions examples/displayio_layout_cartesian_lineplot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# SPDX-FileCopyrightText: 2021 Stefan Krüger
#
# SPDX-License-Identifier: MIT
#############################
"""
This is a basic demonstration of a Cartesian widget for line-ploting
"""

import time
import board
import displayio
from adafruit_displayio_layout.widgets.cartesian import Cartesian

# create the display on the PyPortal or Clue or PyBadge(for example)
display = board.DISPLAY
# otherwise change this to setup the display
# for display chip driver and pinout you have (e.g. ILI9341)

# pybadge display: 160x128
# Create a Cartesian widget
# https://circuitpython.readthedocs.io/projects/displayio-layout/en/latest/api.html#module-adafruit_displayio_layout.widgets.cartesian
my_plane = Cartesian(
x=20, # x position for the plane
y=0, # y plane position
width=130, # display width
height=105, # display height
xrange=(0, 100), # x range
yrange=(0, 100), # y range
)

my_group = displayio.Group()
my_group.append(my_plane)
display.show(my_group) # add high level Group to the display

data = [
(0, 0),
(10, 10),
(30, 10),
(50, 50),
(70, 30),
(90, 80),
(95, 80),
(100, 100),
]

print("examples/displayio_layout_cartesian_lineplot.py")
for x, y in data:
my_plane.update_line(x, y)
time.sleep(1)

while True:
pass