Skip to content

Merge in code from Adafruit_CircuitPython_DisplayIO_Layout v1.17.0 #5

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

Merged
merged 7 commits into from
Feb 19, 2022
Merged
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
235 changes: 181 additions & 54 deletions displayio_cartesian.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@

try:
import bitmaptools
except NameError:
except ImportError:
pass

try:
from typing import Tuple
except ImportError:
Expand Down Expand Up @@ -73,6 +74,7 @@ class Cartesian(Widget):
:param int nudge_y: movement in pixels in the y direction to move the origin.
Defaults to 0

:param bool verbose: print debugging information in some internal functions. Default to False

**Quickstart: Importing and using Cartesian**

Expand Down Expand Up @@ -180,11 +182,14 @@ def __init__(
subticks: bool = False,
nudge_x: int = 0,
nudge_y: int = 0,
verbose: bool = False,
**kwargs,
) -> None:

super().__init__(**kwargs)

self._verbose = verbose

self._background_color = background_color

self._axes_line_color = axes_color
Expand Down Expand Up @@ -249,8 +254,8 @@ def __init__(
self._axesy_bitmap = displayio.Bitmap(self._axesy_width, self.height, 4)
self._axesy_bitmap.fill(0)

self._screen_bitmap = displayio.Bitmap(self.width, self.height, 5)
self._screen_bitmap.fill(5)
self._plot_bitmap = displayio.Bitmap(self.width, self.height, 5)
self.clear_plot_lines()
self._screen_palette = displayio.Palette(6)
self._screen_palette.make_transparent(0)
self._screen_palette[1] = self._tick_color
Expand Down Expand Up @@ -292,7 +297,7 @@ def __init__(
)

self._screen_tilegrid = displayio.TileGrid(
self._screen_bitmap,
self._plot_bitmap,
pixel_shader=self._screen_palette,
x=0,
y=0,
Expand All @@ -309,11 +314,8 @@ def __init__(
self.append(self._screen_tilegrid)
self.append(self._corner_tilegrid)

self._update_line = True

self._pointer = None
self._circle_palette = None
self._pointer_vector_shape = None
self.plot_line_point = None

@staticmethod
Expand Down Expand Up @@ -389,10 +391,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 @@ -448,18 +452,138 @@ def _draw_ticks(self) -> None:
)

def _draw_pointers(self, x: int, y: int) -> None:
self._pointer = vectorio.Circle(self._pointer_radius)
self._circle_palette = displayio.Palette(2)
self._circle_palette.make_transparent(0)
self._circle_palette[1] = self._pointer_color

self._pointer_vector_shape = vectorio.VectorShape(
shape=self._pointer,
pixel_shader=self._circle_palette,
x=x,
y=y,

self._circle_palette = displayio.Palette(1)
self._circle_palette[0] = self._pointer_color
self._pointer = vectorio.Circle(
radius=self._pointer_radius, x=x, y=y, pixel_shader=self._circle_palette
)
self.append(self._pointer_vector_shape)

self.append(self._pointer)

def _calc_local_xy(self, x: int, y: int) -> Tuple[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, local_y = self._calc_local_xy(x, y)
if self._verbose:
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],
)
)
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:
# 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 update_pointer(self, x: int, y: int) -> None:
"""updater_pointer function
Expand All @@ -469,46 +593,49 @@ def update_pointer(self, x: int, y: int) -> None:
: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
)
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]

if local_x >= 0 or local_y <= 100:
if self._update_line:
self._draw_pointers(local_x, local_y)
self._update_line = False
else:
self._pointer_vector_shape.x = local_x
self._pointer_vector_shape.y = local_y
def add_plot_line(self, x: int, y: int) -> None:
"""add_plot_line function.

def _set_plotter_line(self) -> None:
self.plot_line_point = list()
add line to the plane.
multiple calls create a line-plot graph.

def update_line(self, x: int, y: int) -> None:
"""updater_line 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
"""
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._plot_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,
)

def clear_plot_lines(self, palette_index=5):
"""clear_plot_lines function.

clear all added lines
(clear line-plot graph)

:param int palette_index: color palett index. Defaults to 5
:return: None

rtype: None
"""
self.plot_line_point = None
self._plot_bitmap.fill(palette_index)
2 changes: 1 addition & 1 deletion examples/displayio_cartesian_advanced_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import board
import displayio
import terminalio
from adafruit_displayio_layout.widgets.cartesian import Cartesian
from displayio_cartesian import Cartesian

# Fonts used for the Dial tick labels
tick_font = terminalio.FONT
Expand Down
63 changes: 63 additions & 0 deletions examples/displayio_cartesian_lineplot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# 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 displayio_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=15, # x position for the plane
y=2, # y plane position
width=140, # display width
height=105, # display height
xrange=(0, 10), # x range
yrange=(0, 10), # 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), # we do this point manually - so we have no wait...
(1, 1),
(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")

# first point without a wait.
my_plane.add_plot_line(0, 0)
for x, y in data:
my_plane.add_plot_line(x, y)
time.sleep(0.5)

while True:
pass
2 changes: 1 addition & 1 deletion examples/displayio_cartesian_simpletest.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import board
import displayio
import terminalio
from adafruit_displayio_layout.widgets.cartesian import Cartesian
from displayio_cartesian import Cartesian

# Fonts used for the Dial tick labels
tick_font = terminalio.FONT
Expand Down