Skip to content

Commit

Permalink
Add a polar plot example and some minor corrections to other examples. (
Browse files Browse the repository at this point in the history
  • Loading branch information
corranwebster authored Oct 23, 2024
1 parent e61d8a3 commit 13c261e
Show file tree
Hide file tree
Showing 4 changed files with 217 additions and 6 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ updates, and so on.

<img src="./pico-tempe-polar.png" width="480" alt="A Raspberry Pi Pico with a variety of polar plots on the screen" /> <img src="./docs/source/user_guide/polar.png" width="160" alt="A variety of polar plots drawn in an image" />

<img src="./docs/source/user_guide/line_plot_4.png" width="160" alt="A line plot of temperature over time drawn in an image" /> <img src="./docs/source/user_guide/scatter_plot.png" width="160" alt="A scatter plot of environmental data with scales drawn in an image" />
<img src="./docs/source/user_guide/line_plot_4.png" width="160" alt="A line plot of temperature over time drawn in an image" /> <img src="./docs/source/user_guide/scatter_plot.png" width="160" alt="A scatter plot of environmental data with scales drawn in an image" /> <img src="./docs/source/user_guide/polar_plot.png" width="160" alt="A polar plot of air quality data over time in an image" />

## Documentation

Expand Down
Binary file added docs/source/user_guide/polar_plot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
211 changes: 211 additions & 0 deletions examples/polar_plots.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
from array import array
import gc
from math import sqrt, log

from tempe import colors
from tempe.colormaps.viridis import viridis
from tempe.data_view import Range, Repeat
from tempe.geometry import ColumnGeometry, RowGeometry, PointsToLines
from tempe.markers import Marker
from tempe.polar_geometry import polar_points, polar_r_lines
from tempe.surface import Surface


surface = Surface()

# a buffer one third the size of the screen
working_buffer = array('H', bytearray(2*320*81))


# fill the background with off-white pixels
surface.rects('BACKGROUND', [(0, 0, 320, 240)], [colors.grey_1])

class LinearScale:
"""Object that maps data to screen values linearly."""

def __init__(self, low_data, low_screen, high_data, high_screen):
self.low_data = low_data
self.low_screen = low_screen
self.high_data = high_data
self.high_screen = high_screen
data_range = high_data - low_data
screen_range = high_screen - low_screen
self.scale = screen_range / data_range

def scale_values(self, data):
"""Scale data values to screen values."""
screen = array('h', bytearray(2*len(data)))
low_data = self.low_data
low_screen = self.low_screen
scale = self.scale
for i, value in enumerate(data):
screen[i] = int(low_screen + scale * (value - low_data))
return screen

class ColorScale:
"""Object that maps data to color values."""

def __init__(self, colormap, low_data, low_screen, high_data, high_screen):
self.colormap = colormap
self.low_data = low_data
self.low_screen = low_screen
self.high_data = high_data
self.high_screen = high_screen
data_range = high_data - low_data
screen_range = high_screen - low_screen
self.scale = screen_range / data_range

def scale_values(self, data):
"""Scale data values to screen values."""
screen = array('h', bytearray(2*len(data)))
low_data = self.low_data
low_screen = self.low_screen
scale = self.scale
colormap = self.colormap
max_color = len(colormap) - 1
for i, value in enumerate(data):
screen[i] = colormap[max(
min(
int(low_screen + scale * (value - low_data)),
max_color,
),
0,
)]
return screen

gc.collect()
from data.environmental import timestamps, air_quality

# Plot screen bounds
cx = 160
cy = 120
max_r = 100

# Map the data to polar coordinates
air_quality_scale = LinearScale(0, 0, 150, max_r)
time_scale = LinearScale(1729551600, -90, 1729638000, 270)
color_scale = ColorScale(viridis, 1729500000, 0, 1729500000+48*60*60, 255)

thetas = time_scale.scale_values(timestamps)
line_colors = color_scale.scale_values(timestamps)
quality_rs = air_quality_scale.scale_values(air_quality)

# Create polar line geometry for the data points
quality_lines = PointsToLines(polar_points(cx, cy, ColumnGeometry([quality_rs, thetas])))
gc.collect()

# draw the plot
surface.lines(
"DRAWING",
quality_lines,
line_colors,
clip=(cx - max_r, cy - max_r, 2*max_r+1, 2*max_r+1),
)

quality_label_values = [50, 100, 150]
quality_label_rs = air_quality_scale.scale_values(quality_label_values)
time_label_values = [1729551600 + i*3600 for i in range(6, 24, 6)]
time_label_strings = ["9:00", "12:00", "18:00"]
time_label_thetas = time_scale.scale_values(time_label_values)
time_label_rs = [max_r + 8, max_r + 8, max_r + 40]

surface.circles(
"UNDERLAY",
ColumnGeometry([
Repeat(cx),
Repeat(cy),
quality_label_rs,
]),
Repeat(colors.grey_3),
fill=False,
clip=(cx - max_r, cy - max_r, 2*max_r+1, 2*max_r+1),
)
surface.lines(
"UNDERLAY",
polar_r_lines(cx, cy, ColumnGeometry([
Repeat(air_quality_scale.scale_values([50])[0]),
time_scale.scale_values([1729551600 + 3600*i for i in range(24)]),
Repeat(int(air_quality_scale.scale * 100)),
])),
Repeat(colors.grey_3),
clip=(cx - max_r, cy - max_r, 2*max_r+1, 2*max_r+1),
)

quality_label_geometry = polar_points(cx, cy, ColumnGeometry([quality_label_rs, Repeat(270)]))
surface.points(
"OVERLAY",
quality_label_geometry,
Repeat(colors.grey_6),
[f" {value:d} ppb" for value in quality_label_values],
clip=(cx, cy - max_r - 8, 64, 100),
)
time_label_geometry = polar_points(
cx,
cy,
ColumnGeometry([time_label_rs, time_label_thetas]),
)
surface.points(
"OVERLAY",
time_label_geometry,
Repeat(colors.grey_6),
time_label_strings,
clip=(0, 0, 320, 240),
)

# Plot title and additional information
from tempe.fonts import roboto16bold, roboto16
from tempe.font import TempeFont
surface.text(
'DRAWING',
[[4, 0]],
[colors.grey_7],
["Air Quality (ppb)"],
font=TempeFont(roboto16bold),
)
surface.text(
'DRAWING',
[[4, 20]],
[colors.grey_6],
["20/8/24--\n22/8/24"],
font=TempeFont(roboto16),
)

def main(surface, working_buffer):
import asyncio

async def init_display():
from devices.st7789 import ST7789
from machine import Pin, SPI

spi = SPI(0, baudrate=62_500_000, phase=1, polarity=1, sck=Pin(18, Pin.OUT), mosi=Pin(19, Pin.OUT), miso=Pin(16, Pin.OUT))
backlight = Pin(20, Pin.OUT)
display = ST7789(spi, cs_pin=Pin(17, Pin.OUT, value=1), dc_pin=Pin(16, Pin.OUT))
backlight(1)
await display.init()
return display

# set up the display object
display = asyncio.run(init_display())

# refresh the display
display.clear()
import time
start = time.ticks_us()
surface.refresh(display, working_buffer)
print(time.ticks_diff(time.ticks_us(), start))


if __name__ == '__main__':

# # if we have an actual screen, use it
# main(surface, working_buffer)

# elif __name__ != '__test__':
from tempe.display import FileDisplay

# set up the display object
display = FileDisplay('polar_plot.rgb565', (320, 240))
# refresh the display
with display:
display.clear()
surface.refresh(display, working_buffer)
10 changes: 5 additions & 5 deletions examples/scatter_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ def scale_values(self, data):
marker_sizes = humidity_scale.scale_values(humidity)
marker_colors = time_scale.scale_values(timestamps)

# Create line geometry for the data points
# Create point-size geometry for the data points
markers = ColumnGeometry([xs, ys, marker_sizes])

# draw the plot
Expand Down Expand Up @@ -366,14 +366,14 @@ async def init_display():

if __name__ == '__main__':

# if we have an actual screen, use it
main(surface, working_buffer)
# # if we have an actual screen, use it
# main(surface, working_buffer)

elif __name__ != '__test__':
# elif __name__ != '__test__':
from tempe.display import FileDisplay

# set up the display object
display = FileDisplay('line_plot.rgb565', (320, 240))
display = FileDisplay('scatter_plot.rgb565', (320, 240))
# refresh the display
with display:
display.clear()
Expand Down

0 comments on commit 13c261e

Please sign in to comment.